mutant-melbourne 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,298 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius
|
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
|
+
end
|
43
|
+
|
44
|
+
class AccessUndefined < Send
|
45
|
+
transform :kernel, :access_undefined, "VM instruction for undefined"
|
46
|
+
|
47
|
+
def self.match?(line, receiver, name, arguments, privately)
|
48
|
+
if privately and name == :undefined
|
49
|
+
new line, receiver, name, privately
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Handles Rubinius.primitive
|
56
|
+
class SendPrimitive < SendWithArguments
|
57
|
+
transform :default, :primitive, "Rubinius.primitive"
|
58
|
+
|
59
|
+
def self.match?(line, receiver, name, arguments, privately)
|
60
|
+
match_send? receiver, :Rubinius, name, :primitive
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Handles Rubinius.check_frozen
|
66
|
+
class CheckFrozen < SendWithArguments
|
67
|
+
transform :default, :frozen, "Rubinius.check_frozen"
|
68
|
+
|
69
|
+
def self.match?(line, receiver, name, arguments, privately)
|
70
|
+
match_send? receiver, :Rubinius, name, :check_frozen
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Handles Rubinius.invoke_primitive
|
76
|
+
#
|
77
|
+
class InvokePrimitive < SendWithArguments
|
78
|
+
transform :default, :invoke_primitive, "Rubinius.invoke_primitive"
|
79
|
+
|
80
|
+
def self.match?(line, receiver, name, arguments, privately)
|
81
|
+
match_send? receiver, :Rubinius, name, :invoke_primitive
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Handles Rubinius.call_custom
|
87
|
+
#
|
88
|
+
class CallCustom < SendWithArguments
|
89
|
+
transform :default, :call_custom, "Rubinius.call_custom"
|
90
|
+
|
91
|
+
def self.match?(line, receiver, name, arguments, privately)
|
92
|
+
match_send? receiver, :Rubinius, name, :call_custom
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Handles Rubinius.single_block_arg
|
98
|
+
#
|
99
|
+
# Given the following code:
|
100
|
+
#
|
101
|
+
# m { |x| ... }
|
102
|
+
#
|
103
|
+
# In Ruby 1.8, this has the following semantics:
|
104
|
+
#
|
105
|
+
# * x == nil if no values are yielded
|
106
|
+
# * x == val if one value is yielded
|
107
|
+
# * x == [p, q, r, ...] if more than one value is yielded
|
108
|
+
# * x == [a, b, c, ...] if one Array is yielded
|
109
|
+
#
|
110
|
+
# In Ruby 1.9, this has the following semantics:
|
111
|
+
#
|
112
|
+
# * x == nil if no values are yielded
|
113
|
+
# * x == val if one value is yielded
|
114
|
+
# * x == p if yield(p, q, r, ...)
|
115
|
+
# * x == [a, b, c, ...] if one Array is yielded
|
116
|
+
#
|
117
|
+
# However, in Ruby 1.9, the Enumerator code manually implements the 1.8
|
118
|
+
# block argument semantics. This transform exposes the VM instruction we
|
119
|
+
# use in 1.8 mode (cast_for_single_block_arg) so we can use it in 1.9 mode
|
120
|
+
# for Enumerator.
|
121
|
+
#
|
122
|
+
class SingleBlockArg < SendWithArguments
|
123
|
+
transform :default, :single_block_arg, "Rubinius.single_block_arg"
|
124
|
+
|
125
|
+
def self.match?(line, receiver, name, arguments, privately)
|
126
|
+
match_send? receiver, :Rubinius, name, :single_block_arg
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# Handles Rubinius.asm
|
132
|
+
#
|
133
|
+
class InlineAssembly < SendWithArguments
|
134
|
+
transform :default, :assembly, "Rubinius.asm"
|
135
|
+
|
136
|
+
def self.match?(line, receiver, name, arguments, privately)
|
137
|
+
match_send? receiver, :Rubinius, name, :asm
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Handles Rubinius.privately
|
143
|
+
#
|
144
|
+
class SendPrivately < Send
|
145
|
+
transform :kernel, :privately, "Rubinius.privately"
|
146
|
+
|
147
|
+
def self.match?(line, receiver, name, arguments, privately)
|
148
|
+
if match_send? receiver, :Rubinius, name, :privately
|
149
|
+
new line, receiver, name, privately
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def block=(iter)
|
154
|
+
@block = iter.body
|
155
|
+
end
|
156
|
+
|
157
|
+
def map_sends
|
158
|
+
walk do |result, node|
|
159
|
+
case node
|
160
|
+
when Send, SendWithArguments
|
161
|
+
node.privately = true
|
162
|
+
end
|
163
|
+
|
164
|
+
result
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Emits fast VM instructions for certain methods.
|
171
|
+
#
|
172
|
+
class SendFastMath < SendWithArguments
|
173
|
+
transform :default, :fast_math, "VM instructions for math, relational methods"
|
174
|
+
|
175
|
+
Operators = {
|
176
|
+
:+ => :meta_send_op_plus,
|
177
|
+
:- => :meta_send_op_minus,
|
178
|
+
:== => :meta_send_op_equal,
|
179
|
+
:=== => :meta_send_op_tequal,
|
180
|
+
:< => :meta_send_op_lt,
|
181
|
+
:> => :meta_send_op_gt
|
182
|
+
}
|
183
|
+
|
184
|
+
def self.match?(line, receiver, name, arguments, privately)
|
185
|
+
return false unless op = Operators[name]
|
186
|
+
if match_arguments? arguments, 1
|
187
|
+
node = new line, receiver, name, arguments
|
188
|
+
node.operator = op
|
189
|
+
node
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
attr_accessor :operator
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# Emits a fast path for #new
|
198
|
+
#
|
199
|
+
class SendFastNew < SendWithArguments
|
200
|
+
transform :default, :fast_new, "Fast SomeClass.new path"
|
201
|
+
|
202
|
+
# FIXME duplicated from kernel/common/compiled_code.rb
|
203
|
+
KernelMethodSerial = 47
|
204
|
+
|
205
|
+
def self.match?(line, receiver, name, arguments, privately)
|
206
|
+
# ignore vcall style
|
207
|
+
return false if !arguments and privately
|
208
|
+
name == :new
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
##
|
213
|
+
# Emits "safe" names for certain fundamental core library methods
|
214
|
+
#
|
215
|
+
class SendKernelMethod < SendWithArguments
|
216
|
+
transform :kernel, :kernel_methods, "Safe names for fundamental methods"
|
217
|
+
|
218
|
+
Methods = {
|
219
|
+
:/ => :divide,
|
220
|
+
:__slash__ => :/,
|
221
|
+
:class => :__class__
|
222
|
+
}
|
223
|
+
|
224
|
+
Arguments = {
|
225
|
+
:/ => 1,
|
226
|
+
:__slash__ => 1,
|
227
|
+
:class => 0
|
228
|
+
}
|
229
|
+
|
230
|
+
def self.match?(line, receiver, name, arguments, privately)
|
231
|
+
return false unless rename = Methods[name]
|
232
|
+
if match_arguments? arguments, Arguments[name]
|
233
|
+
new line, receiver, rename, arguments, privately
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
##
|
239
|
+
# Maps various methods to VM instructions
|
240
|
+
#
|
241
|
+
class SendInstructionMethod < SendWithArguments
|
242
|
+
transform :default, :fast_system, "VM instructions for certain methods"
|
243
|
+
|
244
|
+
Methods = {
|
245
|
+
:__kind_of__ => :kind_of,
|
246
|
+
:__instance_of__ => :instance_of,
|
247
|
+
:__nil__ => :is_nil,
|
248
|
+
}
|
249
|
+
|
250
|
+
Arguments = {
|
251
|
+
:__kind_of__ => 1,
|
252
|
+
:__instance_of__ => 1,
|
253
|
+
:__nil__ => 0,
|
254
|
+
}
|
255
|
+
|
256
|
+
def self.match?(line, receiver, name, arguments, privately)
|
257
|
+
return false unless rename = Methods[name]
|
258
|
+
if match_arguments? arguments, Arguments[name]
|
259
|
+
new line, receiver, rename, arguments, privately
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
##
|
265
|
+
# Speeds up certain forms of Type.coerce_to
|
266
|
+
#
|
267
|
+
class SendFastCoerceTo < SendWithArguments
|
268
|
+
transform :default, :fast_coerce, "Fast Rubinius::Type.coerce_to path"
|
269
|
+
|
270
|
+
def self.match?(line, receiver, name, arguments, privately)
|
271
|
+
methods = [:coerce_to, :check_convert_type, :try_convert]
|
272
|
+
receiver.kind_of?(TypeConstant) && methods.include?(name) &&
|
273
|
+
arguments.body.size == 3
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
##
|
278
|
+
# Handles loop do ... end
|
279
|
+
#
|
280
|
+
class SendLoop < Send
|
281
|
+
transform :magic, :loop, "loop do ... end"
|
282
|
+
|
283
|
+
def self.match?(line, receiver, name, arguments, privately)
|
284
|
+
if receiver.kind_of? Self and name == :loop
|
285
|
+
new line, receiver, name, privately
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def block=(iter)
|
290
|
+
if iter.kind_of? BlockPass
|
291
|
+
@blockarg = iter
|
292
|
+
else
|
293
|
+
@block = iter.body
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius
|
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 to_sexp
|
14
|
+
[:splat, @value.to_sexp]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ConcatArgs < Node
|
19
|
+
attr_accessor :array, :rest
|
20
|
+
|
21
|
+
def initialize(line, array, rest)
|
22
|
+
@line = line
|
23
|
+
@array = array
|
24
|
+
@rest = rest
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_sexp
|
28
|
+
[:argscat, @array.to_sexp, @rest.to_sexp]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class PushArgs < Node
|
33
|
+
attr_accessor :arguments, :value
|
34
|
+
|
35
|
+
def initialize(line, arguments, value)
|
36
|
+
@line = line
|
37
|
+
@arguments = arguments
|
38
|
+
@value = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_sexp
|
42
|
+
[:argspush, @arguments.to_sexp, @value.to_sexp]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
class SValue < Node
|
48
|
+
attr_accessor :value
|
49
|
+
|
50
|
+
def initialize(line, value)
|
51
|
+
@line = line
|
52
|
+
@value = value
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_sexp
|
56
|
+
[:svalue, @value.to_sexp]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class ToArray < Node
|
61
|
+
attr_accessor :value
|
62
|
+
|
63
|
+
def initialize(line, value)
|
64
|
+
@line = line
|
65
|
+
@value = value
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_sexp
|
69
|
+
[:to_ary, @value.to_sexp]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class ToString < Node
|
74
|
+
attr_accessor :value
|
75
|
+
|
76
|
+
def initialize(line, value)
|
77
|
+
@line = line
|
78
|
+
@value = value
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_sexp
|
82
|
+
sexp = [:evstr]
|
83
|
+
sexp << @value.to_sexp if @value
|
84
|
+
sexp
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius
|
4
|
+
module AST
|
5
|
+
class BackRef < Node
|
6
|
+
attr_accessor :kind
|
7
|
+
|
8
|
+
def initialize(line, ref)
|
9
|
+
@line = line
|
10
|
+
@kind = ref
|
11
|
+
end
|
12
|
+
|
13
|
+
Kinds = {
|
14
|
+
:~ => 0,
|
15
|
+
:& => 1,
|
16
|
+
:"`" => 2,
|
17
|
+
:"'" => 3,
|
18
|
+
:+ => 4
|
19
|
+
}
|
20
|
+
|
21
|
+
def mode
|
22
|
+
unless mode = Kinds[@kind]
|
23
|
+
raise "Unknown backref: #{@kind}"
|
24
|
+
end
|
25
|
+
|
26
|
+
mode
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_sexp
|
30
|
+
[:back_ref, @kind]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class NthRef < Node
|
35
|
+
attr_accessor :which
|
36
|
+
|
37
|
+
def initialize(line, ref)
|
38
|
+
@line = line
|
39
|
+
@which = ref
|
40
|
+
end
|
41
|
+
|
42
|
+
Mode = 5
|
43
|
+
|
44
|
+
def to_sexp
|
45
|
+
[:nth_ref, @which]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class VariableAccess < Node
|
50
|
+
attr_accessor :name
|
51
|
+
|
52
|
+
def initialize(line, name)
|
53
|
+
@line = line
|
54
|
+
@name = name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class VariableAssignment < Node
|
59
|
+
attr_accessor :name, :value
|
60
|
+
|
61
|
+
def initialize(line, name, value)
|
62
|
+
@line = line
|
63
|
+
@name = name
|
64
|
+
@value = value
|
65
|
+
end
|
66
|
+
|
67
|
+
def defined(g)
|
68
|
+
g.push_literal "assignment"
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_sexp
|
72
|
+
sexp = [sexp_name, @name]
|
73
|
+
sexp << @value.to_sexp if @value
|
74
|
+
sexp
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class ClassVariableAccess < VariableAccess
|
79
|
+
def to_sexp
|
80
|
+
[:cvar, @name]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class ClassVariableAssignment < VariableAssignment
|
85
|
+
def sexp_name
|
86
|
+
:cvasgn
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class ClassVariableDeclaration < ClassVariableAssignment
|
91
|
+
def sexp_name
|
92
|
+
:cvdecl
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class CurrentException < Node
|
97
|
+
def to_sexp
|
98
|
+
[:gvar, :$!]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class GlobalVariableAccess < VariableAccess
|
103
|
+
EnglishBackrefs = {
|
104
|
+
:$LAST_MATCH_INFO => :~,
|
105
|
+
:$MATCH => :&,
|
106
|
+
:$PREMATCH => :'`',
|
107
|
+
:$POSTMATCH => :"'",
|
108
|
+
:$LAST_PAREN_MATCH => :+,
|
109
|
+
}
|
110
|
+
|
111
|
+
def self.for_name(line, name)
|
112
|
+
case name
|
113
|
+
when :$!
|
114
|
+
CurrentException.new(line)
|
115
|
+
when :$~
|
116
|
+
BackRef.new(line, :~)
|
117
|
+
else
|
118
|
+
if backref = EnglishBackrefs[name]
|
119
|
+
BackRef.new(line, backref)
|
120
|
+
else
|
121
|
+
new(line, name)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_sexp
|
127
|
+
[:gvar, @name]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class GlobalVariableAssignment < VariableAssignment
|
132
|
+
def sexp_name
|
133
|
+
:gasgn
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class SplatAssignment < Node
|
138
|
+
attr_accessor :value
|
139
|
+
|
140
|
+
def initialize(line, value)
|
141
|
+
@line = line
|
142
|
+
@value = value
|
143
|
+
end
|
144
|
+
|
145
|
+
def to_sexp
|
146
|
+
[:splat_assign, @value.to_sexp]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class SplatArray < SplatAssignment
|
151
|
+
def initialize(line, value, size)
|
152
|
+
@line = line
|
153
|
+
@value = value
|
154
|
+
@size = size
|
155
|
+
end
|
156
|
+
|
157
|
+
def to_sexp
|
158
|
+
[:splat, @value.to_sexp]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class SplatWrapped < SplatAssignment
|
163
|
+
def to_sexp
|
164
|
+
[:splat, @value.to_sexp]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class EmptySplat < Node
|
169
|
+
def initialize(line, size)
|
170
|
+
@line = line
|
171
|
+
@size = size
|
172
|
+
end
|
173
|
+
|
174
|
+
def to_sexp
|
175
|
+
[:splat]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class InstanceVariableAccess < VariableAccess
|
180
|
+
def to_sexp
|
181
|
+
[:ivar, @name]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class InstanceVariableAssignment < VariableAssignment
|
186
|
+
def sexp_name
|
187
|
+
:iasgn
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class LocalVariableAccess < VariableAccess
|
192
|
+
include LocalVariable
|
193
|
+
|
194
|
+
def initialize(line, name)
|
195
|
+
@line = line
|
196
|
+
@name = name
|
197
|
+
@variable = nil
|
198
|
+
end
|
199
|
+
|
200
|
+
def to_sexp
|
201
|
+
[:lvar, @name]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class LocalVariableAssignment < VariableAssignment
|
206
|
+
include LocalVariable
|
207
|
+
|
208
|
+
def initialize(line, name, value)
|
209
|
+
@line = line
|
210
|
+
@name = name
|
211
|
+
@value = value
|
212
|
+
@variable = nil
|
213
|
+
end
|
214
|
+
|
215
|
+
def sexp_name
|
216
|
+
:lasgn
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class PostArg < Node
|
221
|
+
attr_accessor :into, :rest
|
222
|
+
|
223
|
+
def initialize(line, into, rest)
|
224
|
+
@line = line
|
225
|
+
@into = into
|
226
|
+
@rest = rest
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
class MultipleAssignment < Node
|
231
|
+
attr_accessor :left, :right, :splat, :block
|
232
|
+
|
233
|
+
def initialize(line, left, right, splat)
|
234
|
+
@line = line
|
235
|
+
@left = left
|
236
|
+
@right = right
|
237
|
+
@splat = nil
|
238
|
+
@block = nil # support for |&b|
|
239
|
+
@post = nil # in `a,*b,c`, c is in post.
|
240
|
+
|
241
|
+
if Rubinius.ruby18?
|
242
|
+
@fixed = right.kind_of?(ArrayLiteral) ? true : false
|
243
|
+
elsif splat.kind_of?(PostArg)
|
244
|
+
@fixed = false
|
245
|
+
@post = splat.rest
|
246
|
+
splat = splat.into
|
247
|
+
elsif right.kind_of?(ArrayLiteral)
|
248
|
+
@fixed = right.body.size > 1
|
249
|
+
else
|
250
|
+
@fixed = false
|
251
|
+
end
|
252
|
+
|
253
|
+
if splat.kind_of? Node
|
254
|
+
if @left
|
255
|
+
if right
|
256
|
+
@splat = SplatAssignment.new line, splat
|
257
|
+
else
|
258
|
+
@splat = SplatWrapped.new line, splat
|
259
|
+
end
|
260
|
+
elsif @fixed
|
261
|
+
@splat = SplatArray.new line, splat, right.body.size
|
262
|
+
elsif right.kind_of? SplatValue
|
263
|
+
@splat = splat
|
264
|
+
else
|
265
|
+
@splat = SplatWrapped.new line, splat
|
266
|
+
end
|
267
|
+
elsif splat
|
268
|
+
# We need a node for eg { |*| } and { |a, *| }
|
269
|
+
size = @fixed ? right.body.size : 0
|
270
|
+
@splat = EmptySplat.new line, size
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def pad_short(g)
|
275
|
+
short = @left.body.size - @right.body.size
|
276
|
+
if short > 0
|
277
|
+
short.times { g.push :nil }
|
278
|
+
g.make_array 0 if @splat
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def pop_excess(g)
|
283
|
+
excess = @right.body.size - @left.body.size
|
284
|
+
excess.times { g.pop } if excess > 0
|
285
|
+
end
|
286
|
+
|
287
|
+
def make_array(g)
|
288
|
+
size = @right.body.size - @left.body.size
|
289
|
+
g.make_array size if size >= 0
|
290
|
+
end
|
291
|
+
|
292
|
+
def rotate(g)
|
293
|
+
if @splat
|
294
|
+
size = @left.body.size + 1
|
295
|
+
else
|
296
|
+
size = @right.body.size
|
297
|
+
end
|
298
|
+
g.rotate size
|
299
|
+
end
|
300
|
+
|
301
|
+
def iter_arguments
|
302
|
+
@iter_arguments = true
|
303
|
+
end
|
304
|
+
|
305
|
+
def declare_local_scope(scope)
|
306
|
+
# Fix the scope for locals introduced by the left. We
|
307
|
+
# do this before running the code for the right so that
|
308
|
+
# right side sees the proper scoping of the locals on the left.
|
309
|
+
|
310
|
+
if @left
|
311
|
+
@left.body.each do |var|
|
312
|
+
case var
|
313
|
+
when LocalVariable
|
314
|
+
scope.assign_local_reference var
|
315
|
+
when MultipleAssignment
|
316
|
+
var.declare_local_scope(scope)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
if @splat and @splat.kind_of?(SplatAssignment)
|
322
|
+
if @splat.value.kind_of?(LocalVariable)
|
323
|
+
scope.assign_local_reference @splat.value
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def to_sexp
|
329
|
+
left = @left ? @left.to_sexp : [:array]
|
330
|
+
left << [:splat, @splat.to_sexp] if @splat
|
331
|
+
left << @block.to_sexp if @block
|
332
|
+
|
333
|
+
sexp = [:masgn, left]
|
334
|
+
sexp << @right.to_sexp if @right
|
335
|
+
sexp
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
class PatternVariable < Node
|
340
|
+
include LocalVariable
|
341
|
+
|
342
|
+
attr_accessor :name, :value
|
343
|
+
|
344
|
+
def initialize(line, name)
|
345
|
+
@line = line
|
346
|
+
@name = name
|
347
|
+
@variable = nil
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|