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,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
|