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,848 @@
1
+ require 'nodewrap'
2
+
3
+ module Nodewrap
4
+
5
+ # A module for decoding YARV bytecode.
6
+ #
7
+ # This is actually pretty cool. It's actually a miniature VM, where the
8
+ # result of evaluating an expression is itself another expression. This
9
+ # turns out to be much simpler than a full ruby VM, but I think one
10
+ # could use this as a base for building one.
11
+ #
12
+ # Example usage:
13
+ # env = Nodewrap::ByteDecoder::Environment.new(is.local_table)
14
+ # is = VM::InstructionSequence.new('1 + 1')
15
+ # is.bytedecode(env)
16
+ # env.expressions.each do |expr|
17
+ # puts expr
18
+ # end
19
+ # puts stack[-1]
20
+ #
21
+ module ByteDecoder
22
+
23
+ class Environment
24
+ attr_reader :stack
25
+ attr_reader :expressions
26
+ attr_reader :local_table
27
+ attr_accessor :last
28
+ attr_reader :seq
29
+ attr_accessor :pc
30
+
31
+ def initialize(local_table)
32
+ @stack = []
33
+ @expressions = []
34
+ @local_table = local_table
35
+ @last = nil
36
+ @pc = 0
37
+ end
38
+
39
+ def advance(instruction_length)
40
+ @pc += instruction_length
41
+ end
42
+
43
+ def remember(expression)
44
+ if not expression.is_a?(Expression::Literal) then
45
+ @expressions << expression
46
+ end
47
+ end
48
+ end
49
+
50
+ class Expression
51
+ attr_reader :pc
52
+
53
+ def initialize(pc)
54
+ @pc = pc
55
+ end
56
+
57
+ def <=>(rhs)
58
+ return @pc <=> rhs.pc
59
+ end
60
+
61
+ def fmt(arg)
62
+ if arg.respond_to?(:precedence)
63
+ p = arg.precedence
64
+ else
65
+ p = 0
66
+ end
67
+
68
+ if p >= self.precedence then
69
+ return "(#{arg})"
70
+ else
71
+ return arg
72
+ end
73
+ end
74
+
75
+ class Literal < Expression
76
+ attr_reader :value
77
+
78
+ def initialize(pc, value)
79
+ super(pc)
80
+ @value = value
81
+ end
82
+
83
+ def to_s
84
+ case @value
85
+ when Regexp then "/#{@value.inspect[1..-2]}/"
86
+ else; return @value.inspect
87
+ end
88
+ end
89
+
90
+ def precedence
91
+ return 1
92
+ end
93
+ end
94
+
95
+ class Infix < Expression
96
+ attr_reader :op
97
+ attr_reader :lhs
98
+ attr_reader :rhs
99
+
100
+ def initialize(pc, op, lhs, rhs)
101
+ super(pc)
102
+ @op = op
103
+ @lhs = lhs
104
+ @rhs = rhs
105
+ end
106
+
107
+ def to_s
108
+ return "#{fmt(@lhs)} #{@op} #{fmt(@rhs)}"
109
+ end
110
+
111
+ def precedence
112
+ case @op
113
+ when :*, :/, :%
114
+ return 2
115
+ when '+'.intern, '-'.intern
116
+ return 3
117
+ when :<<, :>>
118
+ return 4
119
+ when :>, :>=, :<, :<=, :==, :===
120
+ return 5
121
+ else
122
+ raise ArgumentError, "Unknown op: #{@op}"
123
+ end
124
+ end
125
+ end
126
+
127
+ class Prefix < Expression
128
+ def initialize(pc, op, expr)
129
+ super(pc)
130
+ @op = op
131
+ @expr = expr
132
+ end
133
+
134
+ def to_s
135
+ op = @op.to_s
136
+ op.chop! if op[-1] == ?@
137
+ if @op == '!'.intern and @expr.is_a?(Infix) and @expr.op == :== then
138
+ return "#{@expr.fmt(@expr.lhs)} != #{@expr.fmt(@expr.rhs)}"
139
+ elsif self.precedence < @expr.precedence then
140
+ return "#{op}(#{@expr})"
141
+ else
142
+ return "#{op}#{@expr}"
143
+ end
144
+ end
145
+
146
+ def precedence
147
+ return 1
148
+ end
149
+ end
150
+
151
+ class Send < Expression
152
+ attr_reader :is_assignment
153
+
154
+ def initialize(pc, id, has_receiver, has_parens, receiver, block, splat_last, *args)
155
+ super(pc)
156
+ @id = id
157
+ @is_assignment = id.to_s[-1] == ?=
158
+ @has_receiver = has_receiver
159
+ @has_parens = has_parens
160
+ @receiver = receiver
161
+ @block = block
162
+ @splat_last = splat_last
163
+ @args = args
164
+ end
165
+
166
+ def to_s
167
+ s = ''
168
+ receiver_str = @has_receiver \
169
+ ? "#{@receiver}." \
170
+ : nil
171
+ args = @args.map { |x| x.to_s }
172
+ if @splat_last then
173
+ args[-1] = "*#{@args[-1]}"
174
+ end
175
+ if @is_assignment and args.size == 1 then
176
+ s = "#{receiver_str}#{@id.to_s[0..-2]} = #{args[0]}"
177
+ else
178
+ open = @has_parens ? '(' : ''
179
+ close = @has_parens ? ')' : ''
180
+ s = "#{receiver_str}#{@id}#{open}#{args.join(', ')}#{close}"
181
+ end
182
+ if @block then
183
+ # TODO: this code is duplicated elsewhere
184
+ # TODO: handle block args
185
+ env = Environment.new(@block.local_table)
186
+ @block.bytedecode(env)
187
+ expressions = env.expressions + env.stack
188
+ expressions.sort!
189
+ expressions.map! { |x| x.to_s }
190
+ if expressions.length == 1 and
191
+ expressions[0].is_a?(Literal) and
192
+ expressions[0].value == nil then
193
+ # empty
194
+ else
195
+ s << " { #{expressions.join('; ')} }"
196
+ end
197
+ end
198
+ return s
199
+ end
200
+
201
+ def precedence
202
+ if @has_receiver then
203
+ if @receiver.respond_to?(:precedence) then
204
+ return @receiver.precedence
205
+ end
206
+ end
207
+ return 1
208
+ end
209
+ end
210
+
211
+ class Self < Expression
212
+ def initialize(pc)
213
+ super(pc)
214
+ end
215
+
216
+ def to_s
217
+ return "self"
218
+ end
219
+
220
+ def precedence
221
+ return 1
222
+ end
223
+ end
224
+
225
+ class Hash < Expression
226
+ def initialize(pc, args)
227
+ super(pc)
228
+ @args = args
229
+ end
230
+
231
+ def to_s
232
+ s = '{ '
233
+ a = []
234
+ i = 0
235
+ while i < @args.length do
236
+ a << "#{@args[i]} => #{@args[i + 1]}"
237
+ i += 2
238
+ end
239
+ s << a.join(', ')
240
+ s << ' ' if a.length != 0
241
+ s << '}'
242
+ return s
243
+ end
244
+
245
+ def precedence
246
+ return 1
247
+ end
248
+ end
249
+
250
+ class Array < Expression
251
+ def initialize(pc, args)
252
+ super(pc)
253
+ @args = args
254
+ end
255
+
256
+ def to_s
257
+ s = '[ '
258
+ s << @args.join(', ')
259
+ s << ' ]'
260
+ return s
261
+ end
262
+
263
+ def precedence
264
+ return 1
265
+ end
266
+ end
267
+
268
+ class ConcatArray < Expression
269
+ def initialize(array, splat)
270
+ @array = array
271
+ @splat = splat
272
+ end
273
+
274
+ def to_s
275
+ s = '[ '
276
+ case @array
277
+ when Array then s << @array.args.join(', ')
278
+ when Literal then s << @array.value.join(', ')
279
+ else; raise "Unexpected: #{@array.inspect}"
280
+ end
281
+ s << ', *'
282
+ s << @splat.to_s
283
+ s << ' ]'
284
+ end
285
+
286
+ def precedence
287
+ return 1
288
+ end
289
+ end
290
+
291
+ class Defined < Expression
292
+ def initialize(pc, arg)
293
+ super(pc)
294
+ @arg = arg
295
+ end
296
+
297
+ def to_s
298
+ return "defined?(#{@arg.to_s})"
299
+ end
300
+
301
+ def precedence
302
+ return 1
303
+ end
304
+ end
305
+
306
+ class Variable < Expression
307
+ def initialize(pc, name)
308
+ super(pc)
309
+ @name = name
310
+ end
311
+
312
+ def to_s
313
+ return @name.to_s
314
+ end
315
+
316
+ def precedence
317
+ return 1
318
+ end
319
+ end
320
+
321
+ class Constant < Expression
322
+ def initialize(pc, klass, name)
323
+ super(pc)
324
+ @klass = klass
325
+ @name = name
326
+ end
327
+
328
+ def to_s
329
+ if @klass then
330
+ if @klass == Object then
331
+ return "::#{@name}"
332
+ else
333
+ return "#{@klass}::#{@name}"
334
+ end
335
+ else
336
+ return "#{@name}"
337
+ end
338
+ end
339
+
340
+ def precedence
341
+ return 1
342
+ end
343
+ end
344
+
345
+ class ConstantAssignment < Constant
346
+ def initialize(pc, klass, name, value)
347
+ super(pc, klass, name)
348
+ @value = value
349
+ end
350
+
351
+ def to_s
352
+ s = super()
353
+ s << " = #{@value}"
354
+ return s
355
+ end
356
+ end
357
+
358
+ class ConcatStrings < Expression
359
+ def initialize(pc, args)
360
+ super(pc)
361
+ @args = args
362
+ end
363
+
364
+ def to_s
365
+ s = "\""
366
+ @args.each do |arg|
367
+ case arg
368
+ when Literal
369
+ case arg.value
370
+ when String then s << arg.value
371
+ else; s << arg.to_s
372
+ end
373
+ else
374
+ s << "\#{#{arg.to_s}}"
375
+ end
376
+ end
377
+ s << "\""
378
+ end
379
+
380
+ def precedence
381
+ return 1
382
+ end
383
+ end
384
+
385
+ class Assignment < Expression
386
+ attr_reader :rhs
387
+
388
+ def initialize(pc, name, rhs)
389
+ super(pc)
390
+ @name = name
391
+ @rhs = rhs
392
+ end
393
+
394
+ def to_s
395
+ return "#{@name} = #{@rhs}"
396
+ end
397
+
398
+ def precedence
399
+ return 5
400
+ end
401
+ end
402
+
403
+ class ToRegexp < Expression
404
+ def initialize(pc, value)
405
+ super(pc)
406
+ @value = value
407
+ end
408
+
409
+ def to_s
410
+ case @value
411
+ when ConcatStrings
412
+ string = @value.to_s
413
+ unstring = string[1..-2]
414
+ return Regexp.compile(unstring).inspect
415
+ else
416
+ return Regexp.compile(@value.to_s).inspect
417
+ end
418
+ end
419
+
420
+ def precedence
421
+ return 1
422
+ end
423
+ end
424
+
425
+ class Throw < Expression
426
+ def initialize(pc, value)
427
+ super(pc)
428
+ @value = value
429
+ end
430
+
431
+ def to_s
432
+ # TODO: not all throws are breaks...
433
+ if not @value or (@value.is_a?(Literal) and @value.value == nil) then
434
+ return "break"
435
+ else
436
+ return "break #{@value}"
437
+ end
438
+ end
439
+
440
+ def precedence
441
+ return 1
442
+ end
443
+ end
444
+ end
445
+
446
+ end # ByteDecoder
447
+
448
+ end # Nodewrap
449
+
450
+ class VM
451
+ class Instruction
452
+ include Nodewrap::ByteDecoder
453
+
454
+ class PUTOBJECT
455
+ def bytedecode(env)
456
+ env.stack.push Expression::Literal.new(env.pc, self.operands[0])
457
+ end
458
+ end
459
+
460
+ INFIX_OPCODES = {
461
+ OPT_PLUS => '+'.intern,
462
+ OPT_MINUS => '-'.intern,
463
+ OPT_MULT => :*,
464
+ OPT_DIV => :/,
465
+ OPT_MOD => :%,
466
+ OPT_LTLT => :<<,
467
+ # OPT_GTGT => :>>,
468
+ OPT_EQ => :==,
469
+ OPT_GT => :>,
470
+ OPT_GE => :>=,
471
+ OPT_LT => :<,
472
+ OPT_LE => :<=,
473
+ }
474
+
475
+ INFIX_OPERATORS = INFIX_OPCODES.values + [ :===, :>> ]
476
+
477
+ INFIX_OPCODES.each do |klass, op|
478
+ klass.class_eval do
479
+ define_method(:bytedecode) do |env|
480
+ rhs = env.stack.pop
481
+ lhs = env.stack.pop
482
+ env.stack.push Expression::Infix.new(env.pc, op, lhs, rhs)
483
+ end
484
+ end
485
+ end
486
+
487
+ PREFIX_OPCODES = {
488
+ PUTNOT => '!'.intern,
489
+ }
490
+
491
+ PREFIX_OPERATORS = PREFIX_OPCODES.values + [ :~, :+@, :-@ ]
492
+
493
+ PREFIX_OPCODES.each do |klass, op|
494
+ klass.class_eval do
495
+ define_method(:bytedecode) do |env|
496
+ expr = env.stack.pop
497
+ env.stack.push Expression::Prefix.new(env.pc, op, expr)
498
+ end
499
+ end
500
+ end
501
+
502
+ class TRACE
503
+ def bytedecode(env)
504
+ end
505
+ end
506
+
507
+ class LEAVE
508
+ def bytedecode(env)
509
+ end
510
+ end
511
+
512
+ LITERAL_OPCODES = [
513
+ PUTNIL,
514
+ DUPARRAY,
515
+ PUTSTRING,
516
+ ]
517
+
518
+ LITERAL_OPCODES.each do |klass|
519
+ klass.class_eval do
520
+ define_method(:bytedecode) do |env|
521
+ env.stack.push Expression::Literal.new(env.pc, @operands[0])
522
+ end
523
+ end
524
+ end
525
+
526
+ class SEND
527
+ def bytedecode(env)
528
+ id = @operands[0]
529
+ num_args = @operands[1]
530
+ args = []
531
+ num_args.times do
532
+ args.unshift env.stack.pop
533
+ end
534
+ has_receiver = !flag_set(VM::CALL_FCALL_BIT)
535
+ has_parens = !flag_set(VM::CALL_VCALL_BIT)
536
+ splat_last = flag_set(VM::CALL_ARGS_SPLAT_BIT)
537
+ receiver = env.stack.pop
538
+ block = @operands[2]
539
+ if INFIX_OPERATORS.include?(id) and args.size == 1 then
540
+ env.stack.push Expression::Infix.new(env.pc, id, receiver, args[0])
541
+ elsif PREFIX_OPERATORS.include?(id) and args.size == 0 then
542
+ env.stack.push Expression::Prefix.new(env.pc, id, receiver)
543
+ else
544
+ env.stack.push Expression::Send.new(
545
+ env.pc, id, has_receiver, has_parens, receiver, block, splat_last, *args)
546
+ end
547
+ end
548
+
549
+ def flag_set(flag)
550
+ flags = @operands[3]
551
+ return flags & flag == flag
552
+ end
553
+ end
554
+
555
+ class PUTSELF
556
+ def bytedecode(env)
557
+ env.stack.push Expression::Self.new(env.pc)
558
+ end
559
+ end
560
+
561
+ class NEWHASH
562
+ def bytedecode(env)
563
+ i = @operands[0]
564
+ args = []
565
+ while i > 0 do
566
+ args.unshift env.stack.pop
567
+ i -= 1
568
+ end
569
+ env.stack.push Expression::Hash.new(env.pc, args)
570
+ end
571
+ end
572
+
573
+ class NEWARRAY
574
+ def bytedecode(env)
575
+ i = @operands[0]
576
+ args = []
577
+ while i > 0 do
578
+ args.unshift env.stack.pop
579
+ i -= 1
580
+ end
581
+ env.stack.push Expression::Array.new(env.pc, args)
582
+ end
583
+ end
584
+
585
+ class DEFINED
586
+ def bytedecode(env)
587
+ env.stack.push Expression::Defined.new(env.pc, @operands[1])
588
+ end
589
+ end
590
+
591
+ GET_VARIABLE_OPCODES = [
592
+ GETCLASSVARIABLE,
593
+ GETINSTANCEVARIABLE,
594
+ GETGLOBAL,
595
+ ]
596
+
597
+ GET_VARIABLE_OPCODES.each do |klass|
598
+ klass.class_eval do
599
+ define_method(:bytedecode) do |env|
600
+ env.stack.push Expression::Variable.new(env.pc, @operands[0])
601
+ end
602
+ end
603
+ end
604
+
605
+ SET_VARIABLE_OPCODES = [
606
+ SETCLASSVARIABLE,
607
+ SETINSTANCEVARIABLE,
608
+ SETGLOBAL,
609
+ ]
610
+
611
+ SET_VARIABLE_OPCODES.each do |klass|
612
+ klass.class_eval do
613
+ define_method(:bytedecode) do |env|
614
+ value = env.stack.pop
615
+ env.stack.delete_at(-1) # TODO: dup'd value.. is this right?
616
+ env.stack.push Expression::Assignment.new(env.pc, @operands[0], value)
617
+ end
618
+ end
619
+ end
620
+
621
+ class GETCONSTANT
622
+ def bytedecode(env)
623
+ klass = env.stack.pop
624
+ env.stack.push Expression::Constant.new(env.pc, klass, @operands[0])
625
+ end
626
+ end
627
+
628
+ class SETCONSTANT
629
+ def bytedecode(env)
630
+ klass = env.stack.pop
631
+ value = env.stack.pop
632
+ env.stack.push Expression::ConstantAssignment.new(env.pc, klass, @operands[0], value)
633
+ end
634
+ end
635
+
636
+ class GETSPECIAL
637
+ def bytedecode(env)
638
+ type = @operands[1] >> 1
639
+ type += ?0.ord if type < 10
640
+ env.stack.push Expression::Variable.new(env.pc, "$#{type.chr}")
641
+ end
642
+ end
643
+
644
+ class GETINLINECACHE
645
+ def bytedecode(env)
646
+ env.stack.push nil
647
+ end
648
+ end
649
+
650
+ class SETINLINECACHE
651
+ def bytedecode(env)
652
+ end
653
+ end
654
+
655
+ class NOP
656
+ def bytedecode(env)
657
+ end
658
+ end
659
+
660
+ class TOSTRING
661
+ def bytedecode(env)
662
+ end
663
+ end
664
+
665
+ class CONCATSTRINGS
666
+ def bytedecode(env)
667
+ i = @operands[0]
668
+ args = []
669
+ while i > 0 do
670
+ args.unshift env.stack.pop
671
+ i -= 1
672
+ end
673
+ env.stack.push Expression::ConcatStrings.new(env.pc, args)
674
+ end
675
+ end
676
+
677
+ class TOREGEXP
678
+ def bytedecode(env)
679
+ env.stack.push Expression::ToRegexp.new(env.pc, env.stack.pop)
680
+ end
681
+ end
682
+
683
+ class DUP
684
+ def bytedecode(env)
685
+ arg = env.stack.pop
686
+ env.stack.push arg
687
+ env.stack.push arg
688
+ end
689
+ end
690
+
691
+ class SETLOCAL
692
+ def bytedecode(env)
693
+ idx = env.local_table.size - @operands[0] + 1
694
+ name = env.local_table[idx]
695
+ value = env.stack.pop
696
+ env.stack.push Expression::Assignment.new(env.pc, name, value)
697
+ end
698
+ end
699
+
700
+ class GETLOCAL
701
+ def bytedecode(env)
702
+ idx = env.local_table.size - @operands[0] + 1
703
+ name = env.local_table[idx]
704
+ env.stack.push Expression::Variable.new(env.pc, name)
705
+ end
706
+ end
707
+
708
+ class SETDYNAMIC
709
+ def bytedecode(env)
710
+ idx = env.local_table.size - @operands[0]
711
+ name = env.local_table[idx]
712
+ value = env.stack.pop
713
+ env.stack.push Expression::Assignment.new(env.pc, name, value)
714
+ end
715
+ end
716
+
717
+ class GETDYNAMIC
718
+ def bytedecode(env)
719
+ idx = env.local_table.size - @operands[0]
720
+ name = env.local_table[idx]
721
+ env.stack.push Expression::Variable.new(env.pc, name)
722
+ end
723
+ end
724
+
725
+ class SETN
726
+ # set nth stack entry to stack top
727
+ def bytedecode(env)
728
+ n = @operands[0]
729
+ dest = -(n+1)
730
+ if env.stack[dest].is_a?(Expression) then
731
+ env.remember env.stack[dest]
732
+ end
733
+ env.stack[dest] = env.stack[-1]
734
+ end
735
+ end
736
+
737
+ class POP
738
+ def bytedecode(env)
739
+ top = env.stack[-1]
740
+ if top.is_a?(Expression::Send) and top.is_assignment then
741
+ # special case - the return value from the assignment gets
742
+ # thrown away and the result is the rhs
743
+ env.remember env.stack[-2]
744
+ env.stack.delete_at(-2)
745
+ end
746
+ env.remember top
747
+ env.stack.pop
748
+ end
749
+ end
750
+
751
+ class THROW
752
+ def bytedecode(env)
753
+ value = env.stack.pop
754
+ env.remember env.stack.pop
755
+ env.stack.push Expression::Throw.new(env.pc, value)
756
+ end
757
+ end
758
+
759
+ class CONCATARRAY
760
+ def bytedecode(env)
761
+ splat = env.stack.pop
762
+ array = env.stack.pop
763
+ env.stack.push Expression::ConcatArray.new(array, splat)
764
+ end
765
+ end
766
+ end
767
+
768
+ class InstructionSequence
769
+ def bytedecode(env, start_pc=nil, end_pc=nil)
770
+ self.each do |instruction|
771
+ # p instruction
772
+ if start_pc and env.pc >= start_pc then
773
+ instruction.bytedecode(env)
774
+ end
775
+ # p env.stack
776
+ env.advance(instruction.length)
777
+ break if end_pc and env.pc >= end_pc
778
+ end
779
+ end
780
+
781
+ def opt_pc
782
+ opt_table = self.arg_opt_table
783
+ return opt_table.length > 0 ? opt_table[-1] : 0
784
+ end
785
+ end
786
+ end
787
+
788
+ if __FILE__ == $0 then
789
+ # def foo; @@foo = 1; end
790
+ # def foo; a = [2, 3]; foo(1, *a); end
791
+ # def foo; not true; end
792
+ # def foo; catch(:foo) { throw :foo; 42 }; end
793
+ # def foo; a ? b : c; end
794
+ # def foo; loop { a = 1; break }; end
795
+ # def foo; ::BAR; end
796
+ # def foo; a != b; end
797
+ # def foo; 1 - 2; end
798
+ # def foo; +a; end
799
+ # def foo; !a; end
800
+ # def foo; a << b; end
801
+ # def foo; a === b; end
802
+ # def foo; []; end
803
+ def foo; foo.bar = 42; end
804
+ # def foo; h = {}; h.default = true; h; end
805
+ # def foo; @FOO; end
806
+ # def foo; $FOO; end
807
+ # def foo; /foo#{bar}/; end
808
+ # def foo; /foo/; end
809
+ # def foo; foo = 1; bar=2; baz=3 end
810
+ # def foo; "foo#{bar}"; end
811
+ # def foo; $`; end
812
+ # def foo; FOO; end
813
+ # def foo; @@foo; end
814
+ # def foo; defined?(FOO); end
815
+ # def foo; [1+1, 2, 3, 4] ; end
816
+ # def foo; { 1 => 2, 3 => 4 }; end
817
+ # def foo; foo(1 + 2 * (3 + 4), 5); end
818
+ # def foo; 1 + 2 * (3 + 4); end
819
+
820
+ n = method(:foo).body
821
+ is = n.body
822
+ puts is.disasm
823
+
824
+ env = Nodewrap::ByteDecoder::Environment.new(is.local_table)
825
+ s = ''
826
+ # puts "local_table = #{is.local_table.inspect}"
827
+ is.each do |i|
828
+ # p i.operand_types, i.operand_names
829
+ # p i #, i.operand_types, i.operand_names
830
+ print i.class, ' '
831
+ a = []
832
+ i.operand_names.each_with_index do |name, idx|
833
+ a << "#{name}(#{i.operand_types[idx]})=#{i.operands[idx].inspect}"
834
+ end
835
+ puts a.join(', ')
836
+ i.bytedecode(env)
837
+ env.advance(i.length)
838
+ # p env.stack
839
+ # p env.stack.map { |x| x.to_s }
840
+ # puts
841
+ end
842
+
843
+ puts "---"
844
+ (env.expressions + env.stack).sort.each do |expr|
845
+ puts expr.to_s
846
+ end
847
+ end
848
+