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,389 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class Node
6
+ attr_accessor :line
7
+
8
+ def self.transform(category, name, comment)
9
+ Transforms.register category, name, self
10
+ @transform_name = name
11
+ @transform_comment = comment
12
+ @transform_kind = :call
13
+ end
14
+
15
+ def self.transform_name
16
+ @transform_name
17
+ end
18
+
19
+ def self.transform_comment
20
+ @transform_comment
21
+ end
22
+
23
+ def self.transform_kind
24
+ @transform_kind
25
+ end
26
+
27
+ def self.transform_kind=(k)
28
+ @transform_kind = k
29
+ end
30
+
31
+ def self.match_send?(node, receiver, method, name)
32
+ node.kind_of? ConstantAccess and
33
+ node.name == receiver and
34
+ method == name
35
+ end
36
+
37
+ def self.match_arguments?(arguments, count)
38
+ case arguments
39
+ when ArrayLiteral
40
+ arguments.body.size == count
41
+ when nil
42
+ count == 0
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ def initialize(line)
49
+ @line = line
50
+ end
51
+
52
+ def pos(g)
53
+ g.set_line @line
54
+ end
55
+
56
+ def new_block_generator(g, arguments)
57
+ blk = g.class.new
58
+ blk.name = g.state.name || :__block__
59
+ blk.file = g.file
60
+ blk.for_block = true
61
+
62
+ blk.required_args = arguments.required_args
63
+ blk.post_args = arguments.post_args
64
+ blk.total_args = arguments.total_args
65
+ blk.splat_index = arguments.splat_index
66
+ blk.block_index = arguments.block_index
67
+
68
+ blk
69
+ end
70
+
71
+ def new_generator(g, name, arguments=nil)
72
+ meth = g.class.new
73
+ meth.name = name
74
+ meth.file = g.file
75
+
76
+ if arguments
77
+ meth.required_args = arguments.required_args
78
+ meth.post_args = arguments.post_args
79
+ meth.total_args = arguments.total_args
80
+ meth.splat_index = arguments.splat_index
81
+ meth.block_index = arguments.block_index
82
+ end
83
+
84
+ meth
85
+ end
86
+
87
+ def bytecode(g)
88
+ end
89
+
90
+ def defined(g)
91
+ g.push_rubinius
92
+ g.push_scope
93
+ g.send :active_path, 0
94
+ g.push @line
95
+ g.send :unrecognized_defined, 2
96
+ g.pop
97
+ g.push :nil
98
+ end
99
+
100
+ def value_defined(g, f)
101
+ bytecode(g)
102
+ end
103
+
104
+ # This method implements a sort of tree iterator, yielding each Node
105
+ # instance to the provided block with the first argument to #walk. If
106
+ # the block returns a non-true value, the walk is terminated.
107
+ #
108
+ # This method is really an iterator, not a Visitor pattern.
109
+ def walk(arg=true, &block)
110
+ children do |child|
111
+ if ch_arg = block.call(arg, child)
112
+ child.walk(ch_arg, &block)
113
+ end
114
+ end
115
+ end
116
+
117
+ def ascii_graph
118
+ AsciiGrapher.new(self).print
119
+ end
120
+
121
+ # Called if used as the lhs of an ||=. Expected to yield if the
122
+ # value was not found, so the bytecode for it to be emitted.
123
+ def or_bytecode(g)
124
+ found = g.new_label
125
+ bytecode(g)
126
+ g.dup
127
+ g.git found
128
+ g.pop
129
+ yield
130
+ found.set!
131
+ end
132
+
133
+ def to_sexp
134
+ [:node, self.class.name]
135
+ end
136
+
137
+ # Yields each child of this Node to the block. Additionally, for any
138
+ # attribute that is an Array, yields each element that is a Node.
139
+ def children
140
+ instance_variables.each do |var|
141
+ child = instance_variable_get var
142
+ if child.kind_of? Node
143
+ yield child
144
+ elsif child.kind_of? Array
145
+ child.each { |x| yield x if x.kind_of? Node }
146
+ end
147
+ end
148
+ end
149
+
150
+ # The equivalent of Some::Module.demodulize.underscore in ActiveSupport.
151
+ # The code is shamelessly borrowed as well.
152
+ def node_name
153
+ name = self.class.name.gsub(/^.*::/, '')
154
+ name.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
155
+ name.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
156
+ name.downcase!
157
+ name
158
+ end
159
+
160
+ # Supports the Visitor pattern on a tree of Nodes. The +visitor+ should
161
+ # be an object that responds to methods named after the Node subclasses.
162
+ # The method called is determined by the #node_name method. Passes both
163
+ # the node and its parent so that the visitor can maintain nesting
164
+ # information if desired.
165
+ #
166
+ # The #visit implements a read-only traversal of the tree. To modify the
167
+ # tree, see the #transform methed.
168
+ def visit(visitor, parent=nil)
169
+ visitor.__send__ self.node_name, self, parent
170
+ children { |c| c.visit visitor, self }
171
+ end
172
+
173
+ # Called by #transform to update the child of a Node instance. The
174
+ # default just calls the attr_accessor for the child. However, Node
175
+ # subclasses that must synchronize other internal state can override
176
+ # this method.
177
+ def set_child(name, node)
178
+ send :"#{name}=", node
179
+ end
180
+
181
+ # Yields each attribute and its name to the block.
182
+ def attributes
183
+ instance_variables.each do |var|
184
+ child = instance_variable_get var
185
+ name = var.to_s[1..-1]
186
+ yield child, name
187
+ end
188
+ end
189
+
190
+ # A fixed-point algorithm for transforming an AST with a visitor. The
191
+ # traversal is top-down. The visitor object's method corresponding to
192
+ # each node (see #node_name) is called for each node, passing the node
193
+ # and its parent.
194
+ #
195
+ # To replace the node in the tree, the visitor method should return a
196
+ # new node; otherwise, return the existing node. The visitor is free to
197
+ # change values in the node, but substituting a node causes the entire
198
+ # tree to be walked repeatedly until no modifications are made.
199
+ def transform(visitor, parent=nil, state=nil)
200
+ state ||= TransformState.new
201
+
202
+ node = visitor.send :"node_#{node_name}", self, parent
203
+ state.modify unless equal? node
204
+
205
+ node.attributes do |attr, name|
206
+ if attr.kind_of? Node
207
+ child = attr.transform visitor, node, state
208
+ unless attr.equal? child
209
+ state.modify
210
+ node.set_child name, child
211
+ end
212
+ elsif attr.kind_of? Array
213
+ attr.each_with_index do |x, i|
214
+ if x.kind_of? Node
215
+ child = x.transform visitor, node, state
216
+ unless x.equal? child
217
+ state.modify
218
+ attr[i] = child
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ # Repeat the walk until the tree is not modified.
226
+ if parent.nil? and state.modified?
227
+ state.unmodify
228
+ node = transform visitor, nil, state
229
+ end
230
+
231
+ node
232
+ end
233
+
234
+ # Manage the state of the #transform method.
235
+ class TransformState
236
+ def initialized
237
+ @modified = false
238
+ end
239
+
240
+ def modified?
241
+ @modified
242
+ end
243
+
244
+ def modify
245
+ @modified = true
246
+ end
247
+
248
+ def unmodify
249
+ @modified = false
250
+ end
251
+ end
252
+ end
253
+
254
+ # In a perfect world, each AST node would fully encapsulate its state. But
255
+ # in the real world, some state exists across the AST rather than just in
256
+ # a node. For example, some nodes need to emit different bytecode when in
257
+ # a rescue.
258
+ #
259
+ # This class maintains state needed as the AST is walked to generate
260
+ # bytecode. An instance of State is pushed onto a stack in the Generator
261
+ # instance as each ClosedScope or Iter is entered, and popped when left.
262
+ class State
263
+ attr_reader :scope, :super, :eval
264
+ attr_accessor :check_for_locals
265
+
266
+ class << self
267
+ attr_accessor :flip_flops
268
+ end
269
+
270
+ self.flip_flops ||= 0
271
+
272
+ def initialize(scope)
273
+ @scope = scope
274
+ @ensure = 0
275
+ @block = 0
276
+ @masgn = 0
277
+ @loop = 0
278
+ @op_asgn = 0
279
+ @rescue = []
280
+ @name = []
281
+ @check_for_locals = true
282
+ end
283
+
284
+ def push_name(name)
285
+ @name.push name
286
+ end
287
+
288
+ def pop_name
289
+ @name.pop
290
+ end
291
+
292
+ def name
293
+ @name.last
294
+ end
295
+
296
+ def push_rescue(val)
297
+ @rescue.push(val)
298
+ end
299
+
300
+ def pop_rescue
301
+ @rescue.pop if rescue?
302
+ end
303
+
304
+ def rescue?
305
+ @rescue.last
306
+ end
307
+
308
+ def push_ensure
309
+ @ensure += 1
310
+ end
311
+
312
+ def pop_ensure
313
+ @ensure -= 1 if ensure?
314
+ end
315
+
316
+ def ensure?
317
+ @ensure > 0
318
+ end
319
+
320
+ def push_block
321
+ @block += 1
322
+ end
323
+
324
+ def pop_block
325
+ @block -= 1 if block?
326
+ end
327
+
328
+ def block?
329
+ @block > 0
330
+ end
331
+
332
+ def flip_flops
333
+ State.flip_flops
334
+ end
335
+
336
+ def push_flip_flop
337
+ State.flip_flops += 1
338
+ end
339
+
340
+ def push_masgn
341
+ @masgn += 1
342
+ end
343
+
344
+ def pop_masgn
345
+ @masgn -= 1 if masgn?
346
+ end
347
+
348
+ def masgn?
349
+ @masgn > 0
350
+ end
351
+
352
+ def push_op_asgn
353
+ @op_asgn += 1
354
+ end
355
+
356
+ def pop_op_asgn
357
+ @op_asgn -= 1 if op_asgn?
358
+ end
359
+
360
+ def op_asgn?
361
+ @op_asgn > 0
362
+ end
363
+
364
+ def push_super(scope)
365
+ @super = scope
366
+ end
367
+
368
+ alias_method :super?, :super
369
+
370
+ def push_eval(scope)
371
+ @eval = scope
372
+ end
373
+
374
+ alias_method :eval?, :eval
375
+
376
+ def push_loop
377
+ @loop += 1
378
+ end
379
+
380
+ def pop_loop
381
+ @loop -= 1 if loop?
382
+ end
383
+
384
+ def loop?
385
+ @loop > 0
386
+ end
387
+ end
388
+ end
389
+ end
@@ -0,0 +1,394 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class And < Node
6
+ attr_accessor :left, :right
7
+
8
+ def initialize(line, left, right)
9
+ @line = line
10
+ @left = left
11
+ @right = right
12
+ end
13
+
14
+ def bytecode(g, use_gif=true)
15
+ @left.bytecode(g)
16
+ g.dup
17
+ lbl = g.new_label
18
+
19
+ if use_gif
20
+ g.gif lbl
21
+ else
22
+ g.git lbl
23
+ end
24
+
25
+ g.pop
26
+ @right.bytecode(g)
27
+ lbl.set!
28
+ end
29
+
30
+ def defined(g)
31
+ t = g.new_label
32
+ f = g.new_label
33
+ done = g.new_label
34
+
35
+ case @left
36
+ when GlobalVariableAccess, InstanceVariableAccess
37
+ g.goto t
38
+ else
39
+ @left.value_defined(g, f)
40
+ g.pop
41
+ end
42
+
43
+ case @right
44
+ when GlobalVariableAccess, InstanceVariableAccess
45
+ g.goto t
46
+ else
47
+ @right.value_defined(g, f)
48
+ g.pop
49
+ end
50
+
51
+ t.set!
52
+ g.push_literal "expression"
53
+ g.string_dup
54
+ g.goto done
55
+
56
+ f.set!
57
+ g.push :nil
58
+
59
+ done.set!
60
+ end
61
+
62
+ def sexp_name
63
+ :and
64
+ end
65
+
66
+ def to_sexp
67
+ [sexp_name, @left.to_sexp, @right.to_sexp]
68
+ end
69
+ end
70
+
71
+ class Or < And
72
+ def bytecode(g)
73
+ super(g, false)
74
+ end
75
+
76
+ def sexp_name
77
+ :or
78
+ end
79
+ end
80
+
81
+ class Not < Node
82
+ attr_accessor :value
83
+
84
+ def initialize(line, value)
85
+ @line = line
86
+ @value = value
87
+ end
88
+
89
+ def bytecode(g)
90
+ true_label = g.new_label
91
+ end_label = g.new_label
92
+
93
+ @value.bytecode(g)
94
+ g.git true_label
95
+
96
+ g.push :true
97
+ g.goto end_label
98
+
99
+ true_label.set!
100
+ g.push :false
101
+ end_label.set!
102
+ end
103
+
104
+ def defined(g)
105
+ t = g.new_label
106
+ f = g.new_label
107
+ done = g.new_label
108
+
109
+ case @value
110
+ when GlobalVariableAccess, InstanceVariableAccess
111
+ g.goto t
112
+ else
113
+ @value.value_defined(g, f)
114
+ g.pop
115
+ end
116
+
117
+ t.set!
118
+ g.push_literal "expression"
119
+ g.goto done
120
+
121
+ f.set!
122
+ g.push :nil
123
+
124
+ done.set!
125
+ end
126
+
127
+ def to_sexp
128
+ [:not, @value.to_sexp]
129
+ end
130
+ end
131
+
132
+ class OpAssign1 < Node
133
+ attr_accessor :receiver, :op, :arguments, :value
134
+
135
+ def initialize(line, receiver, arguments, op, value)
136
+ @line = line
137
+ @receiver = receiver
138
+ @op = op
139
+ arguments = nil if arguments.is_a?(EmptyArray)
140
+ @arguments = ActualArguments.new line, arguments
141
+ @value = value
142
+ end
143
+
144
+ def bytecode(g)
145
+ pos(g)
146
+
147
+ # X: Snippet used for explanation: h[:a] += 3
148
+ # X: given h = { :a => 2 }
149
+ # X: Pull h onto the stack
150
+ @receiver.bytecode(g)
151
+ # X: Pull :a in
152
+ @arguments.bytecode(g)
153
+ recv_stack = @arguments.stack_size + 1
154
+
155
+ # Dup the receiver and arguments to use later
156
+ g.dup_many recv_stack
157
+
158
+ #
159
+ # X: Call [](:a) on h
160
+ #
161
+ # @arguments.size will be 1
162
+
163
+ if @arguments.splat?
164
+ g.push :nil
165
+ g.send_with_splat :[], @arguments.size
166
+ else
167
+ g.send :[], @arguments.size
168
+ end
169
+
170
+ # X: 2 is now on the top of the stack (TOS)
171
+
172
+ # A special case, where we use the value as boolean
173
+ if @op == :or or @op == :and
174
+ fnd = g.new_label
175
+ fin = g.new_label
176
+
177
+ # We dup the value from [] to leave it as the value of the
178
+ # expression
179
+
180
+ g.dup
181
+ if @op == :or
182
+ g.git fnd
183
+ else
184
+ g.gif fnd
185
+ end
186
+
187
+ # Ok, take the extra copy off and pull the value onto the stack
188
+ g.pop
189
+
190
+ # The receiver and arguments are still on the stack
191
+
192
+ @value.bytecode(g)
193
+
194
+ # retain the rhs as the expression value
195
+ g.dup
196
+ g.move_down recv_stack + 1
197
+
198
+ if @arguments.splat?
199
+ g.send :push, 1
200
+ g.push :nil
201
+ g.send_with_splat :[]=, @arguments.size
202
+ else
203
+ g.send :[]=, @arguments.size + 1
204
+ end
205
+ g.pop
206
+
207
+ # Leaves the value we moved down the stack on the top
208
+ g.goto fin
209
+
210
+ fnd.set!
211
+
212
+ # Clean up the stack but retain return value from :[]
213
+ g.move_down recv_stack
214
+ g.pop_many recv_stack
215
+
216
+ fin.set!
217
+ else
218
+ # @op is something like + or -
219
+ # We pull in @value to the stack
220
+ @value.bytecode(g)
221
+ # X: 3 TOS
222
+
223
+ # ... then call it as an argument to @or, called on the return
224
+ # from [].
225
+ # X: 2 + 3
226
+
227
+ g.send @op, 1
228
+ # X: 5 TOS
229
+
230
+ # The new value is on the stack now. It is the last argument to the call
231
+ # to []= because your dupd versions of recv and arguments are still on the stack.
232
+
233
+ # retain the rhs as the expression value
234
+ g.dup
235
+ g.move_down recv_stack + 1
236
+
237
+ # X: Call []=(:a, 5) on h
238
+ if @arguments.splat?
239
+ g.send :push, 1
240
+ g.push :nil
241
+ g.send_with_splat :[]=, @arguments.size
242
+ else
243
+ g.send :[]=, @arguments.size + 1
244
+ end
245
+ g.pop
246
+ end
247
+ end
248
+
249
+ def to_sexp
250
+ arguments = [:arglist] + @arguments.to_sexp
251
+ op = @op == :or ? :"||" : :"&&"
252
+ [:op_asgn1, @receiver.to_sexp, arguments, op, @value.to_sexp]
253
+ end
254
+ end
255
+
256
+ class OpAssign2 < Node
257
+ attr_accessor :receiver, :name, :assign, :op, :value
258
+
259
+ def initialize(line, receiver, name, op, value)
260
+ @line = line
261
+ @receiver = receiver
262
+ @name = name
263
+ @op = op
264
+ @value = value
265
+ @assign = name.to_s[-1] == ?= ? name : :"#{name}="
266
+ end
267
+
268
+ def bytecode(g)
269
+ pos(g)
270
+
271
+ # X: h[:a] += 3, given h.a == 2
272
+ @receiver.bytecode(g)
273
+ # X: TOS = h
274
+ g.dup
275
+ g.send @name, 0
276
+ # X: TOS = 2
277
+
278
+ if @op == :or or @op == :and
279
+ fnd = g.new_label
280
+ fin = g.new_label
281
+
282
+ g.dup
283
+ if @op == :or
284
+ g.git fnd
285
+ else
286
+ g.gif fnd
287
+ end
288
+
289
+ # Remove the copy of 2 and push @value on the stack
290
+ g.pop
291
+ @value.bytecode(g)
292
+
293
+ # Retain the this value to use as the expression value
294
+ g.dup
295
+ g.move_down 2
296
+
297
+ # Call the assignement method, passing @value as the argument
298
+ g.send @assign, 1
299
+ g.pop
300
+
301
+ g.goto fin
302
+
303
+ fnd.set!
304
+
305
+ # Clean up the stack
306
+ g.swap
307
+ g.pop
308
+
309
+ fin.set!
310
+ else
311
+ @value.bytecode(g)
312
+ # X: TOS = 3
313
+ # X: 2 + 3
314
+ g.send @op, 1
315
+
316
+ # Retain the this value to use as the expression value
317
+ g.dup
318
+ g.move_down 2
319
+ # X: TOS = 5
320
+ g.send @assign, 1
321
+ # X: TOS = 5 (or whatever a=() returns)
322
+
323
+ # Discard the methods return value
324
+ g.pop
325
+ end
326
+ end
327
+
328
+ def to_sexp
329
+ op = @op == :or ? :"||" : :"&&"
330
+ [:op_asgn2, @receiver.to_sexp, :"#{@name}=", op, @value.to_sexp]
331
+ end
332
+ end
333
+
334
+ class OpAssignAnd < Node
335
+ attr_accessor :left, :right
336
+
337
+ def initialize(line, left, right)
338
+ @line = line
339
+ @left = left
340
+ @right = right
341
+ end
342
+
343
+ def bytecode(g)
344
+ pos(g)
345
+
346
+ @left.bytecode(g)
347
+ lbl = g.new_label
348
+ g.dup
349
+ g.gif lbl
350
+ g.pop
351
+ @right.bytecode(g)
352
+ lbl.set!
353
+ end
354
+
355
+ def defined(g)
356
+ g.push_literal "assignment"
357
+ end
358
+
359
+ def sexp_name
360
+ :op_asgn_and
361
+ end
362
+
363
+ def to_sexp
364
+ [sexp_name, @left.to_sexp, @right.to_sexp]
365
+ end
366
+ end
367
+
368
+ class OpAssignOr < OpAssignAnd
369
+ def bytecode(g)
370
+ pos(g)
371
+
372
+ @left.or_bytecode(g) do
373
+ @right.bytecode(g)
374
+ end
375
+ end
376
+
377
+ def sexp_name
378
+ :op_asgn_or
379
+ end
380
+ end
381
+
382
+ class OpAssignOr19 < OpAssignOr
383
+ def bytecode(g)
384
+ pos(g)
385
+
386
+ g.state.push_op_asgn
387
+ @left.or_bytecode(g) do
388
+ g.state.pop_op_asgn
389
+ @right.bytecode(g)
390
+ end
391
+ end
392
+ end
393
+ end
394
+ end