rubinius-ast 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,371 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ module Transforms
6
+ def self.register(category, name, klass)
7
+ transform_map[name] = klass
8
+ category_map[category] << klass
9
+ end
10
+
11
+ def self.transform_map
12
+ @transform_map ||= { }
13
+ end
14
+
15
+ def self.category_map
16
+ @category_map ||= Hash.new { |h, k| h[k] = [] }
17
+ end
18
+
19
+ def self.[](name)
20
+ transform_map[name]
21
+ end
22
+
23
+ def self.category(name)
24
+ if name == :all
25
+ category_map.values.flatten
26
+ else
27
+ category_map[name]
28
+ end
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Handles block_given?
34
+ class BlockGiven < Send
35
+ transform :default, :block_given, "VM instruction for block_given?, iterator?"
36
+
37
+ def self.match?(line, receiver, name, arguments, privately)
38
+ if receiver.kind_of? Self and (name == :block_given? or name == :iterator?)
39
+ new line, receiver, name, privately
40
+ end
41
+ end
42
+
43
+ def bytecode(g)
44
+ pos(g)
45
+ g.push_has_block
46
+ end
47
+ end
48
+
49
+ class AccessUndefined < Send
50
+ transform :kernel, :access_undefined, "VM instruction for undefined"
51
+
52
+ def self.match?(line, receiver, name, arguments, privately)
53
+ if privately and name == :undefined
54
+ new line, receiver, name, privately
55
+ end
56
+ end
57
+
58
+ def bytecode(g)
59
+ pos(g)
60
+ g.push_undef
61
+ end
62
+ end
63
+
64
+ ##
65
+ # Handles Rubinius.primitive
66
+ class SendPrimitive < SendWithArguments
67
+ transform :default, :primitive, "Rubinius.primitive"
68
+
69
+ def self.match?(line, receiver, name, arguments, privately)
70
+ match_send? receiver, :Rubinius, name, :primitive
71
+ end
72
+
73
+ def bytecode(g)
74
+ g.send_primitive @arguments.array.first.value
75
+ end
76
+ end
77
+
78
+ ##
79
+ # Handles Rubinius.check_frozen
80
+ class CheckFrozen < SendWithArguments
81
+ transform :default, :frozen, "Rubinius.check_frozen"
82
+
83
+ def self.match?(line, receiver, name, arguments, privately)
84
+ match_send? receiver, :Rubinius, name, :check_frozen
85
+ end
86
+
87
+ def bytecode(g)
88
+ pos(g)
89
+ if @arguments.array.size == 0
90
+ g.push_self
91
+ g.check_frozen
92
+ else
93
+ @arguments.array.first.bytecode(g)
94
+ g.check_frozen
95
+ end
96
+ end
97
+ end
98
+
99
+ ##
100
+ # Handles Rubinius.invoke_primitive
101
+ #
102
+ class InvokePrimitive < SendWithArguments
103
+ transform :default, :invoke_primitive, "Rubinius.invoke_primitive"
104
+
105
+ def self.match?(line, receiver, name, arguments, privately)
106
+ match_send? receiver, :Rubinius, name, :invoke_primitive
107
+ end
108
+
109
+ def bytecode(g)
110
+ if @arguments.splat?
111
+ raise CompileError, "splat argument passed to invoke_primitive"
112
+ elsif @block
113
+ raise CompileError, "block passed to invoke_primitive"
114
+ end
115
+
116
+ pos(g)
117
+ selector = @arguments.array.shift
118
+ @arguments.bytecode(g)
119
+ g.invoke_primitive selector.value, @arguments.size
120
+ end
121
+ end
122
+
123
+ ##
124
+ # Handles Rubinius.call_custom
125
+ #
126
+ class CallCustom < SendWithArguments
127
+ transform :default, :call_custom, "Rubinius.call_custom"
128
+
129
+ def self.match?(line, receiver, name, arguments, privately)
130
+ match_send? receiver, :Rubinius, name, :call_custom
131
+ end
132
+
133
+ def bytecode(g)
134
+ if @arguments.splat?
135
+ raise CompileError, "splat argument passed to call_custom"
136
+ elsif @block
137
+ raise CompileError, "block passed to call_custom"
138
+ end
139
+
140
+ pos(g)
141
+ rec = @arguments.array.shift
142
+ rec.bytecode(g)
143
+
144
+ selector = @arguments.array.shift
145
+ @arguments.bytecode(g)
146
+ g.call_custom selector.value, @arguments.size
147
+ end
148
+ end
149
+
150
+ ##
151
+ # Handles Rubinius.single_block_arg
152
+ #
153
+ # Given the following code:
154
+ #
155
+ # m { |x| ... }
156
+ #
157
+ # In Ruby 1.8, this has the following semantics:
158
+ #
159
+ # * x == nil if no values are yielded
160
+ # * x == val if one value is yielded
161
+ # * x == [p, q, r, ...] if more than one value is yielded
162
+ # * x == [a, b, c, ...] if one Array is yielded
163
+ #
164
+ # In Ruby 1.9, this has the following semantics:
165
+ #
166
+ # * x == nil if no values are yielded
167
+ # * x == val if one value is yielded
168
+ # * x == p if yield(p, q, r, ...)
169
+ # * x == [a, b, c, ...] if one Array is yielded
170
+ #
171
+ # However, in Ruby 1.9, the Enumerator code manually implements the 1.8
172
+ # block argument semantics. This transform exposes the VM instruction we
173
+ # use in 1.8 mode (cast_for_single_block_arg) so we can use it in 1.9 mode
174
+ # for Enumerator.
175
+ #
176
+ class SingleBlockArg < SendWithArguments
177
+ transform :default, :single_block_arg, "Rubinius.single_block_arg"
178
+
179
+ def self.match?(line, receiver, name, arguments, privately)
180
+ match_send? receiver, :Rubinius, name, :single_block_arg
181
+ end
182
+
183
+ def bytecode(g)
184
+ if @arguments.splat?
185
+ raise CompileError, "splat argument passed to single_block_arg"
186
+ elsif @block
187
+ raise CompileError, "block passed to single_block_arg"
188
+ end
189
+
190
+ pos(g)
191
+ g.cast_for_single_block_arg
192
+ end
193
+ end
194
+
195
+ ##
196
+ # Handles Rubinius.asm
197
+ #
198
+ class InlineAssembly < SendWithArguments
199
+ transform :default, :assembly, "Rubinius.asm"
200
+
201
+ def self.match?(line, receiver, name, arguments, privately)
202
+ match_send? receiver, :Rubinius, name, :asm
203
+ end
204
+
205
+ def bytecode(g)
206
+ e = Evaluator.new g, @block.arguments.names, @arguments.array
207
+ e.execute @block.body
208
+ end
209
+ end
210
+
211
+ ##
212
+ # Handles Rubinius.privately
213
+ #
214
+ class SendPrivately < Send
215
+ transform :kernel, :privately, "Rubinius.privately"
216
+
217
+ def self.match?(line, receiver, name, arguments, privately)
218
+ if match_send? receiver, :Rubinius, name, :privately
219
+ new line, receiver, name, privately
220
+ end
221
+ end
222
+
223
+ def block=(iter)
224
+ @block = iter.body
225
+ end
226
+
227
+ def map_sends
228
+ walk do |result, node|
229
+ case node
230
+ when Send, SendWithArguments
231
+ node.privately = true
232
+ end
233
+
234
+ result
235
+ end
236
+ end
237
+
238
+ def bytecode(g)
239
+ map_sends
240
+
241
+ pos(g)
242
+ @block.bytecode(g)
243
+ end
244
+ end
245
+
246
+ ##
247
+ # Emits a fast path for #new
248
+ #
249
+ class SendFastNew < SendWithArguments
250
+ transform :default, :fast_new, "Fast SomeClass.new path"
251
+
252
+ # FIXME duplicated from kernel/common/compiled_code.rb
253
+ KernelMethodSerial = 47
254
+
255
+ def self.match?(line, receiver, name, arguments, privately)
256
+ # ignore vcall style
257
+ return false if !arguments and privately
258
+ name == :new
259
+ end
260
+
261
+ def bytecode(g)
262
+ return super(g) if @block or @arguments.splat?
263
+
264
+ pos(g)
265
+
266
+ slow = g.new_label
267
+ done = g.new_label
268
+
269
+ @receiver.bytecode(g)
270
+ g.dup
271
+
272
+ if @privately
273
+ g.check_serial_private :new, KernelMethodSerial
274
+ else
275
+ g.check_serial :new, KernelMethodSerial
276
+ end
277
+ g.gif slow
278
+
279
+ # fast path
280
+ g.send :allocate, 0, true
281
+ g.dup
282
+ @arguments.bytecode(g)
283
+ g.send :initialize, @arguments.size, true
284
+ g.pop
285
+
286
+ g.goto done
287
+
288
+ # slow path
289
+ slow.set!
290
+ @arguments.bytecode(g)
291
+ g.send :new, @arguments.size, @privately
292
+
293
+ done.set!
294
+ end
295
+ end
296
+
297
+ ##
298
+ # Emits "safe" names for certain fundamental core library methods
299
+ #
300
+ class SendKernelMethod < SendWithArguments
301
+ transform :kernel, :kernel_methods, "Safe names for fundamental methods"
302
+
303
+ Methods = {
304
+ :/ => :divide,
305
+ :__slash__ => :/,
306
+ :class => :__class__
307
+ }
308
+
309
+ Arguments = {
310
+ :/ => 1,
311
+ :__slash__ => 1,
312
+ :class => 0
313
+ }
314
+
315
+ def self.match?(line, receiver, name, arguments, privately)
316
+ return false unless rename = Methods[name]
317
+ if match_arguments? arguments, Arguments[name]
318
+ new line, receiver, rename, arguments, privately
319
+ end
320
+ end
321
+
322
+ def bytecode(g)
323
+ pos(g)
324
+ @receiver.bytecode(g)
325
+ @arguments.bytecode(g)
326
+
327
+ g.send @name, @arguments.size, @privately
328
+ end
329
+ end
330
+
331
+ ##
332
+ # Speeds up certain forms of Type.coerce_to
333
+ #
334
+ class SendFastCoerceTo < SendWithArguments
335
+ transform :default, :fast_coerce, "Fast Rubinius::Type.coerce_to path"
336
+
337
+ def self.match?(line, receiver, name, arguments, privately)
338
+ methods = [:coerce_to, :check_convert_type, :try_convert]
339
+ receiver.kind_of?(TypeConstant) && methods.include?(name) &&
340
+ arguments.body.size == 3
341
+ end
342
+
343
+ def bytecode(g)
344
+ pos(g)
345
+ var = @arguments.array[0]
346
+ const = @arguments.array[1]
347
+
348
+ if (var.kind_of?(LocalVariableAccess) ||
349
+ var.kind_of?(InstanceVariableAccess)) and
350
+ (const.kind_of?(ConstantAccess) ||
351
+ const.kind_of?(ScopedConstant) ||
352
+ const.kind_of?(ToplevelConstant))
353
+ done = g.new_label
354
+
355
+ var.bytecode(g)
356
+ g.dup
357
+ const.bytecode(g)
358
+ g.swap
359
+ g.kind_of
360
+ g.git done
361
+ g.pop
362
+ super(g)
363
+
364
+ done.set!
365
+ else
366
+ super(g)
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
@@ -0,0 +1,182 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class SplatValue < Node
6
+ attr_accessor :value
7
+
8
+ def initialize(line, value)
9
+ @line = line
10
+ @value = value
11
+ end
12
+
13
+ def bytecode(g)
14
+ @value.bytecode(g)
15
+ g.cast_array unless @value.kind_of? ArrayLiteral
16
+ end
17
+
18
+ def to_sexp
19
+ [:splat, @value.to_sexp]
20
+ end
21
+
22
+ def splat?
23
+ true
24
+ end
25
+ end
26
+
27
+ class ConcatArgs < Node
28
+ attr_accessor :array, :rest
29
+
30
+ def initialize(line, array, rest)
31
+ @line = line
32
+ @array = array
33
+ @rest = rest
34
+ end
35
+
36
+ def bytecode(g)
37
+ if @array
38
+ @array.bytecode(g)
39
+ @rest.bytecode(g)
40
+ g.cast_array
41
+ g.send :+, 1
42
+ else
43
+ @rest.bytecode(g)
44
+ g.cast_array
45
+ end
46
+ end
47
+
48
+ # Dive down and try to find an array of regular values
49
+ # that could construct the left side of a concatination.
50
+ # This is used to minimize the splat doing a send.
51
+ def peel_lhs
52
+ case @array
53
+ when ConcatArgs
54
+ @array.peel_lhs
55
+ when ArrayLiteral
56
+ ary = @array.body
57
+ @array = nil
58
+ ary
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ def to_sexp
65
+ [:argscat, @array.to_sexp, @rest.to_sexp]
66
+ end
67
+
68
+ def splat?
69
+ true
70
+ end
71
+ end
72
+
73
+ class PushArgs < Node
74
+ attr_accessor :arguments, :value
75
+
76
+ def initialize(line, arguments, value)
77
+ @line = line
78
+ @arguments = arguments
79
+ @value = value
80
+ end
81
+
82
+ def bytecode(g)
83
+ @arguments.bytecode(g)
84
+ @value.bytecode(g)
85
+ g.make_array 1
86
+ g.send :+, 1
87
+ end
88
+
89
+ def to_sexp
90
+ [:argspush, @arguments.to_sexp, @value.to_sexp]
91
+ end
92
+
93
+ def size
94
+ 1
95
+ end
96
+
97
+ def splat?
98
+ @arguments.splat?
99
+ end
100
+ end
101
+
102
+
103
+ class SValue < Node
104
+ attr_accessor :value
105
+
106
+ def initialize(line, value)
107
+ @line = line
108
+ @value = value
109
+ end
110
+
111
+ def bytecode(g)
112
+ @value.bytecode(g)
113
+ if @value.kind_of? SplatValue
114
+ done = g.new_label
115
+
116
+ g.dup
117
+ g.send :size, 0
118
+ g.push 1
119
+ g.send :>, 1
120
+ g.git done
121
+
122
+ g.push 0
123
+ g.send :at, 1
124
+
125
+ done.set!
126
+ end
127
+ end
128
+
129
+ def to_sexp
130
+ [:svalue, @value.to_sexp]
131
+ end
132
+ end
133
+
134
+ class ToArray < Node
135
+ attr_accessor :value
136
+
137
+ def initialize(line, value)
138
+ @line = line
139
+ @value = value
140
+ end
141
+
142
+ def bytecode(g)
143
+ pos(g)
144
+
145
+ @value.bytecode(g)
146
+ g.cast_multi_value
147
+ end
148
+
149
+ def to_sexp
150
+ [:to_ary, @value.to_sexp]
151
+ end
152
+ end
153
+
154
+ class ToString < Node
155
+ attr_accessor :value
156
+
157
+ def initialize(line, value)
158
+ @line = line
159
+ @value = value
160
+ end
161
+
162
+ def bytecode(g)
163
+ pos(g)
164
+
165
+ @value.bytecode(g)
166
+ g.meta_to_s
167
+ end
168
+
169
+ def value_defined(g, f)
170
+ if @value
171
+ @value.value_defined(g, f)
172
+ end
173
+ end
174
+
175
+ def to_sexp
176
+ sexp = [:evstr]
177
+ sexp << @value.to_sexp if @value
178
+ sexp
179
+ end
180
+ end
181
+ end
182
+ end