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,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
+