mutant-melbourne 2.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.
- data/LICENSE +25 -0
- data/README.md +69 -0
- data/Rakefile +14 -0
- data/ext/melbourne/.gitignore +3 -0
- data/ext/melbourne/bstring-license.txt +29 -0
- data/ext/melbourne/bstrlib.c +2687 -0
- data/ext/melbourne/bstrlib.h +267 -0
- data/ext/melbourne/encoding_compat.cpp +188 -0
- data/ext/melbourne/encoding_compat.hpp +57 -0
- data/ext/melbourne/extconf.rb +87 -0
- data/ext/melbourne/grammar18.cpp +11280 -0
- data/ext/melbourne/grammar18.hpp +13 -0
- data/ext/melbourne/grammar18.y +6088 -0
- data/ext/melbourne/grammar19.cpp +12420 -0
- data/ext/melbourne/grammar19.hpp +11 -0
- data/ext/melbourne/grammar19.y +7113 -0
- data/ext/melbourne/lex.c.blt +152 -0
- data/ext/melbourne/lex.c.tab +136 -0
- data/ext/melbourne/local_state.hpp +43 -0
- data/ext/melbourne/melbourne.cpp +88 -0
- data/ext/melbourne/melbourne.hpp +19 -0
- data/ext/melbourne/node18.hpp +262 -0
- data/ext/melbourne/node19.hpp +271 -0
- data/ext/melbourne/node_types.rb +304 -0
- data/ext/melbourne/node_types18.cpp +255 -0
- data/ext/melbourne/node_types18.hpp +129 -0
- data/ext/melbourne/node_types19.cpp +249 -0
- data/ext/melbourne/node_types19.hpp +126 -0
- data/ext/melbourne/parser_state18.hpp +181 -0
- data/ext/melbourne/parser_state19.hpp +251 -0
- data/ext/melbourne/quark.cpp +42 -0
- data/ext/melbourne/quark.hpp +45 -0
- data/ext/melbourne/symbols.cpp +224 -0
- data/ext/melbourne/symbols.hpp +119 -0
- data/ext/melbourne/var_table18.cpp +83 -0
- data/ext/melbourne/var_table18.hpp +33 -0
- data/ext/melbourne/var_table19.cpp +65 -0
- data/ext/melbourne/var_table19.hpp +35 -0
- data/ext/melbourne/visitor18.cpp +963 -0
- data/ext/melbourne/visitor18.hpp +12 -0
- data/ext/melbourne/visitor19.cpp +960 -0
- data/ext/melbourne/visitor19.hpp +15 -0
- data/lib/compiler/ast/constants.rb +81 -0
- data/lib/compiler/ast/control_flow.rb +290 -0
- data/lib/compiler/ast/data.rb +14 -0
- data/lib/compiler/ast/definitions.rb +749 -0
- data/lib/compiler/ast/encoding.rb +18 -0
- data/lib/compiler/ast/exceptions.rb +138 -0
- data/lib/compiler/ast/file.rb +11 -0
- data/lib/compiler/ast/grapher.rb +89 -0
- data/lib/compiler/ast/literals.rb +207 -0
- data/lib/compiler/ast/node.rb +362 -0
- data/lib/compiler/ast/operators.rb +106 -0
- data/lib/compiler/ast/self.rb +15 -0
- data/lib/compiler/ast/sends.rb +615 -0
- data/lib/compiler/ast/transforms.rb +298 -0
- data/lib/compiler/ast/values.rb +88 -0
- data/lib/compiler/ast/variables.rb +351 -0
- data/lib/compiler/ast.rb +20 -0
- data/lib/compiler/locals.rb +109 -0
- data/lib/melbourne/processor.rb +651 -0
- data/lib/melbourne/version.rb +3 -0
- data/lib/melbourne.rb +143 -0
- metadata +112 -0
@@ -0,0 +1,362 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius
|
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
|
+
|
66
|
+
blk
|
67
|
+
end
|
68
|
+
|
69
|
+
def new_generator(g, name, arguments=nil)
|
70
|
+
meth = g.class.new
|
71
|
+
meth.name = name
|
72
|
+
meth.file = g.file
|
73
|
+
|
74
|
+
if arguments
|
75
|
+
meth.required_args = arguments.required_args
|
76
|
+
meth.post_args = arguments.post_args
|
77
|
+
meth.total_args = arguments.total_args
|
78
|
+
meth.splat_index = arguments.splat_index
|
79
|
+
end
|
80
|
+
|
81
|
+
meth
|
82
|
+
end
|
83
|
+
|
84
|
+
# This method implements a sort of tree iterator, yielding each Node
|
85
|
+
# instance to the provided block with the first argument to #walk. If
|
86
|
+
# the block returns a non-true value, the walk is terminated.
|
87
|
+
#
|
88
|
+
# This method is really an iterator, not a Visitor pattern.
|
89
|
+
def walk(arg=true, &block)
|
90
|
+
children do |child|
|
91
|
+
if ch_arg = block.call(arg, child)
|
92
|
+
child.walk(ch_arg, &block)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def ascii_graph
|
98
|
+
AsciiGrapher.new(self).print
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_sexp
|
102
|
+
[:node, self.class.name]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Yields each child of this Node to the block. Additionally, for any
|
106
|
+
# attribute that is an Array, yields each element that is a Node.
|
107
|
+
def children
|
108
|
+
instance_variables.each do |var|
|
109
|
+
child = instance_variable_get var
|
110
|
+
if child.kind_of? Node
|
111
|
+
yield child
|
112
|
+
elsif child.kind_of? Array
|
113
|
+
child.each { |x| yield x if x.kind_of? Node }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# The equivalent of Some::Module.demodulize.underscore in ActiveSupport.
|
119
|
+
# The code is shamelessly borrowed as well.
|
120
|
+
def self.node_name
|
121
|
+
@node_name ||=
|
122
|
+
begin
|
123
|
+
name = self.name.gsub(/^.*::/, '')
|
124
|
+
name.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
125
|
+
name.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
126
|
+
name.downcase!
|
127
|
+
name
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def node_name
|
132
|
+
self.class.node_name
|
133
|
+
end
|
134
|
+
|
135
|
+
# Supports the Visitor pattern on a tree of Nodes. The +visitor+ should
|
136
|
+
# be an object that responds to methods named after the Node subclasses.
|
137
|
+
# The method called is determined by the #node_name method. Passes both
|
138
|
+
# the node and its parent so that the visitor can maintain nesting
|
139
|
+
# information if desired.
|
140
|
+
#
|
141
|
+
# The #visit implements a read-only traversal of the tree. To modify the
|
142
|
+
# tree, see the #transform methed.
|
143
|
+
def visit(visitor, parent=nil)
|
144
|
+
visitor.__send__ self.node_name, self, parent
|
145
|
+
children { |c| c.visit visitor, self }
|
146
|
+
end
|
147
|
+
|
148
|
+
# Called by #transform to update the child of a Node instance. The
|
149
|
+
# default just calls the attr_accessor for the child. However, Node
|
150
|
+
# subclasses that must synchronize other internal state can override
|
151
|
+
# this method.
|
152
|
+
def set_child(name, node)
|
153
|
+
send :"#{name}=", node
|
154
|
+
end
|
155
|
+
|
156
|
+
# Yields each attribute and its name to the block.
|
157
|
+
def attributes
|
158
|
+
instance_variables.each do |var|
|
159
|
+
child = instance_variable_get var
|
160
|
+
name = var.to_s[1..-1]
|
161
|
+
yield child, name
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# A fixed-point algorithm for transforming an AST with a visitor. The
|
166
|
+
# traversal is top-down. The visitor object's method corresponding to
|
167
|
+
# each node (see #node_name) is called for each node, passing the node
|
168
|
+
# and its parent.
|
169
|
+
#
|
170
|
+
# To replace the node in the tree, the visitor method should return a
|
171
|
+
# new node; otherwise, return the existing node. The visitor is free to
|
172
|
+
# change values in the node, but substituting a node causes the entire
|
173
|
+
# tree to be walked repeatedly until no modifications are made.
|
174
|
+
def transform(visitor, parent=nil, state=nil)
|
175
|
+
state ||= TransformState.new
|
176
|
+
|
177
|
+
node = visitor.send :"node_#{node_name}", self, parent
|
178
|
+
state.modify unless equal? node
|
179
|
+
|
180
|
+
node.attributes do |attr, name|
|
181
|
+
if attr.kind_of? Node
|
182
|
+
child = attr.transform visitor, node, state
|
183
|
+
unless attr.equal? child
|
184
|
+
state.modify
|
185
|
+
node.set_child name, child
|
186
|
+
end
|
187
|
+
elsif attr.kind_of? Array
|
188
|
+
attr.each_with_index do |x, i|
|
189
|
+
if x.kind_of? Node
|
190
|
+
child = x.transform visitor, node, state
|
191
|
+
unless x.equal? child
|
192
|
+
state.modify
|
193
|
+
attr[i] = child
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Repeat the walk until the tree is not modified.
|
201
|
+
if parent.nil? and state.modified?
|
202
|
+
state.unmodify
|
203
|
+
node = transform visitor, nil, state
|
204
|
+
end
|
205
|
+
|
206
|
+
node
|
207
|
+
end
|
208
|
+
|
209
|
+
# Manage the state of the #transform method.
|
210
|
+
class TransformState
|
211
|
+
def initialized
|
212
|
+
@modified = false
|
213
|
+
end
|
214
|
+
|
215
|
+
def modified?
|
216
|
+
@modified
|
217
|
+
end
|
218
|
+
|
219
|
+
def modify
|
220
|
+
@modified = true
|
221
|
+
end
|
222
|
+
|
223
|
+
def unmodify
|
224
|
+
@modified = false
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# In a perfect world, each AST node would fully encapsulate its state. But
|
230
|
+
# in the real world, some state exists across the AST rather than just in
|
231
|
+
# a node. For example, some nodes need to emit different bytecode when in
|
232
|
+
# a rescue.
|
233
|
+
#
|
234
|
+
# This class maintains state needed as the AST is walked to generate
|
235
|
+
# bytecode. An instance of State is pushed onto a stack in the Generator
|
236
|
+
# instance as each ClosedScope or Iter is entered, and popped when left.
|
237
|
+
class State
|
238
|
+
attr_reader :scope, :super, :eval
|
239
|
+
|
240
|
+
class << self
|
241
|
+
attr_accessor :flip_flops
|
242
|
+
end
|
243
|
+
|
244
|
+
self.flip_flops ||= 0
|
245
|
+
|
246
|
+
def initialize(scope)
|
247
|
+
@scope = scope
|
248
|
+
@ensure = 0
|
249
|
+
@block = 0
|
250
|
+
@masgn = 0
|
251
|
+
@loop = 0
|
252
|
+
@op_asgn = 0
|
253
|
+
@rescue = []
|
254
|
+
@name = []
|
255
|
+
end
|
256
|
+
|
257
|
+
def push_name(name)
|
258
|
+
@name.push name
|
259
|
+
end
|
260
|
+
|
261
|
+
def pop_name
|
262
|
+
@name.pop
|
263
|
+
end
|
264
|
+
|
265
|
+
def name
|
266
|
+
@name.last
|
267
|
+
end
|
268
|
+
|
269
|
+
def push_rescue(val)
|
270
|
+
@rescue.push(val)
|
271
|
+
end
|
272
|
+
|
273
|
+
def pop_rescue
|
274
|
+
@rescue.pop if rescue?
|
275
|
+
end
|
276
|
+
|
277
|
+
def rescue?
|
278
|
+
@rescue.last
|
279
|
+
end
|
280
|
+
|
281
|
+
def push_ensure
|
282
|
+
@ensure += 1
|
283
|
+
end
|
284
|
+
|
285
|
+
def pop_ensure
|
286
|
+
@ensure -= 1 if ensure?
|
287
|
+
end
|
288
|
+
|
289
|
+
def ensure?
|
290
|
+
@ensure > 0
|
291
|
+
end
|
292
|
+
|
293
|
+
def push_block
|
294
|
+
@block += 1
|
295
|
+
end
|
296
|
+
|
297
|
+
def pop_block
|
298
|
+
@block -= 1 if block?
|
299
|
+
end
|
300
|
+
|
301
|
+
def block?
|
302
|
+
@block > 0
|
303
|
+
end
|
304
|
+
|
305
|
+
def flip_flops
|
306
|
+
State.flip_flops
|
307
|
+
end
|
308
|
+
|
309
|
+
def push_flip_flop
|
310
|
+
State.flip_flops += 1
|
311
|
+
end
|
312
|
+
|
313
|
+
def push_masgn
|
314
|
+
@masgn += 1
|
315
|
+
end
|
316
|
+
|
317
|
+
def pop_masgn
|
318
|
+
@masgn -= 1 if masgn?
|
319
|
+
end
|
320
|
+
|
321
|
+
def masgn?
|
322
|
+
@masgn > 0
|
323
|
+
end
|
324
|
+
|
325
|
+
def push_op_asgn
|
326
|
+
@op_asgn += 1
|
327
|
+
end
|
328
|
+
|
329
|
+
def pop_op_asgn
|
330
|
+
@op_asgn -= 1 if op_asgn?
|
331
|
+
end
|
332
|
+
|
333
|
+
def op_asgn?
|
334
|
+
@op_asgn > 0
|
335
|
+
end
|
336
|
+
|
337
|
+
def push_super(scope)
|
338
|
+
@super = scope
|
339
|
+
end
|
340
|
+
|
341
|
+
alias_method :super?, :super
|
342
|
+
|
343
|
+
def push_eval(scope)
|
344
|
+
@eval = scope
|
345
|
+
end
|
346
|
+
|
347
|
+
alias_method :eval?, :eval
|
348
|
+
|
349
|
+
def push_loop
|
350
|
+
@loop += 1
|
351
|
+
end
|
352
|
+
|
353
|
+
def pop_loop
|
354
|
+
@loop -= 1 if loop?
|
355
|
+
end
|
356
|
+
|
357
|
+
def loop?
|
358
|
+
@loop > 0
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius
|
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 sexp_name
|
15
|
+
:and
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_sexp
|
19
|
+
[sexp_name, @left.to_sexp, @right.to_sexp]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Or < And
|
24
|
+
def sexp_name
|
25
|
+
:or
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Not < Node
|
30
|
+
attr_accessor :value
|
31
|
+
|
32
|
+
def initialize(line, value)
|
33
|
+
@line = line
|
34
|
+
@value = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_sexp
|
38
|
+
[:not, @value.to_sexp]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class OpAssign1 < Node
|
43
|
+
attr_accessor :receiver, :op, :arguments, :value
|
44
|
+
|
45
|
+
def initialize(line, receiver, arguments, op, value)
|
46
|
+
@line = line
|
47
|
+
@receiver = receiver
|
48
|
+
@op = op
|
49
|
+
arguments = nil if arguments.is_a?(EmptyArray)
|
50
|
+
@arguments = ActualArguments.new line, arguments
|
51
|
+
@value = value
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_sexp
|
55
|
+
arguments = [:arglist] + @arguments.to_sexp
|
56
|
+
op = @op == :or ? :"||" : :"&&"
|
57
|
+
[:op_asgn1, @receiver.to_sexp, arguments, op, @value.to_sexp]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class OpAssign2 < Node
|
62
|
+
attr_accessor :receiver, :name, :assign, :op, :value
|
63
|
+
|
64
|
+
def initialize(line, receiver, name, op, value)
|
65
|
+
@line = line
|
66
|
+
@receiver = receiver
|
67
|
+
@name = name
|
68
|
+
@op = op
|
69
|
+
@value = value
|
70
|
+
@assign = name.to_s[-1] == ?= ? name : :"#{name}="
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_sexp
|
74
|
+
op = @op == :or ? :"||" : :"&&"
|
75
|
+
[:op_asgn2, @receiver.to_sexp, :"#{@name}=", op, @value.to_sexp]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class OpAssignAnd < Node
|
80
|
+
attr_accessor :left, :right
|
81
|
+
|
82
|
+
def initialize(line, left, right)
|
83
|
+
@line = line
|
84
|
+
@left = left
|
85
|
+
@right = right
|
86
|
+
end
|
87
|
+
|
88
|
+
def sexp_name
|
89
|
+
:op_asgn_and
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_sexp
|
93
|
+
[sexp_name, @left.to_sexp, @right.to_sexp]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class OpAssignOr < OpAssignAnd
|
98
|
+
def sexp_name
|
99
|
+
:op_asgn_or
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class OpAssignOr19 < OpAssignOr
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|