rubinius-ast 1.0.1

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.
@@ -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