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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/rubinius/ast/constants.rb +324 -0
- data/lib/rubinius/ast/control_flow.rb +698 -0
- data/lib/rubinius/ast/data.rb +30 -0
- data/lib/rubinius/ast/definitions.rb +1134 -0
- data/lib/rubinius/ast/encoding.rb +26 -0
- data/lib/rubinius/ast/exceptions.rb +545 -0
- data/lib/rubinius/ast/file.rb +18 -0
- data/lib/rubinius/ast/grapher.rb +89 -0
- data/lib/rubinius/ast/literals.rb +555 -0
- data/lib/rubinius/ast/node.rb +389 -0
- data/lib/rubinius/ast/operators.rb +394 -0
- data/lib/rubinius/ast/self.rb +25 -0
- data/lib/rubinius/ast/sends.rb +1028 -0
- data/lib/rubinius/ast/transforms.rb +371 -0
- data/lib/rubinius/ast/values.rb +182 -0
- data/lib/rubinius/ast/variables.rb +842 -0
- data/lib/rubinius/ast/version.rb +5 -0
- data/lib/rubinius/ast.rb +18 -0
- data/rubinius-ast.gemspec +22 -0
- metadata +96 -0
@@ -0,0 +1,842 @@
|
|
1
|
+
# -*- encoding: us-ascii -*-
|
2
|
+
|
3
|
+
module Rubinius::ToolSet.current::TS
|
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 bytecode(g)
|
30
|
+
pos(g)
|
31
|
+
g.last_match mode, 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def defined(g)
|
35
|
+
if @kind == :~
|
36
|
+
g.push_literal "global-variable"
|
37
|
+
g.string_dup
|
38
|
+
return
|
39
|
+
end
|
40
|
+
|
41
|
+
f = g.new_label
|
42
|
+
done = g.new_label
|
43
|
+
|
44
|
+
g.last_match mode, 0
|
45
|
+
g.is_nil
|
46
|
+
g.git f
|
47
|
+
|
48
|
+
g.push_literal "$#{@kind}"
|
49
|
+
g.string_dup
|
50
|
+
|
51
|
+
g.goto done
|
52
|
+
|
53
|
+
f.set!
|
54
|
+
g.push :nil
|
55
|
+
|
56
|
+
done.set!
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_sexp
|
60
|
+
[:back_ref, @kind]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class NthRef < Node
|
65
|
+
attr_accessor :which
|
66
|
+
|
67
|
+
def initialize(line, ref)
|
68
|
+
@line = line
|
69
|
+
@which = ref
|
70
|
+
end
|
71
|
+
|
72
|
+
Mode = 5
|
73
|
+
|
74
|
+
def bytecode(g)
|
75
|
+
pos(g)
|
76
|
+
|
77
|
+
# These are for $1, $2, etc. We subtract 1 because
|
78
|
+
# we start numbering the captures from 0.
|
79
|
+
g.last_match Mode, @which - 1
|
80
|
+
end
|
81
|
+
|
82
|
+
def defined(g)
|
83
|
+
f = g.new_label
|
84
|
+
done = g.new_label
|
85
|
+
|
86
|
+
g.last_match Mode, @which - 1
|
87
|
+
g.is_nil
|
88
|
+
g.git f
|
89
|
+
|
90
|
+
g.push_literal "$#{@which}"
|
91
|
+
g.string_dup
|
92
|
+
|
93
|
+
g.goto done
|
94
|
+
|
95
|
+
f.set!
|
96
|
+
g.push :nil
|
97
|
+
|
98
|
+
done.set!
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_sexp
|
102
|
+
[:nth_ref, @which]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class VariableAccess < Node
|
107
|
+
attr_accessor :name
|
108
|
+
|
109
|
+
def initialize(line, name)
|
110
|
+
@line = line
|
111
|
+
@name = name
|
112
|
+
end
|
113
|
+
|
114
|
+
def value_defined(g, f)
|
115
|
+
variable_defined(g, f)
|
116
|
+
bytecode(g)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class VariableAssignment < Node
|
121
|
+
attr_accessor :name, :value
|
122
|
+
|
123
|
+
def initialize(line, name, value)
|
124
|
+
@line = line
|
125
|
+
@name = name
|
126
|
+
@value = value
|
127
|
+
end
|
128
|
+
|
129
|
+
def defined(g)
|
130
|
+
g.push_literal "assignment"
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_sexp
|
134
|
+
sexp = [sexp_name, @name]
|
135
|
+
sexp << @value.to_sexp if @value
|
136
|
+
sexp
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class ClassVariableAccess < VariableAccess
|
141
|
+
def or_bytecode(g)
|
142
|
+
pos(g)
|
143
|
+
|
144
|
+
done = g.new_label
|
145
|
+
notfound = g.new_label
|
146
|
+
|
147
|
+
variable_defined(g, notfound)
|
148
|
+
|
149
|
+
# Ok, we know the value exists, get it.
|
150
|
+
bytecode(g)
|
151
|
+
g.dup
|
152
|
+
g.git done
|
153
|
+
g.pop
|
154
|
+
|
155
|
+
# yield to generate the code for when it's not found
|
156
|
+
notfound.set!
|
157
|
+
yield
|
158
|
+
|
159
|
+
done.set!
|
160
|
+
end
|
161
|
+
|
162
|
+
def bytecode(g)
|
163
|
+
pos(g)
|
164
|
+
|
165
|
+
push_scope(g)
|
166
|
+
g.send :class_variable_get, 1
|
167
|
+
end
|
168
|
+
|
169
|
+
def push_scope(g)
|
170
|
+
if g.state.scope.module?
|
171
|
+
g.push :self
|
172
|
+
else
|
173
|
+
g.push_scope
|
174
|
+
end
|
175
|
+
g.push_literal @name
|
176
|
+
end
|
177
|
+
|
178
|
+
def variable_defined(g, f)
|
179
|
+
push_scope(g)
|
180
|
+
g.send :class_variable_defined?, 1
|
181
|
+
g.gif f
|
182
|
+
end
|
183
|
+
|
184
|
+
def defined(g)
|
185
|
+
f = g.new_label
|
186
|
+
done = g.new_label
|
187
|
+
|
188
|
+
variable_defined(g, f)
|
189
|
+
g.push_literal "class variable"
|
190
|
+
g.goto done
|
191
|
+
|
192
|
+
f.set!
|
193
|
+
g.push :nil
|
194
|
+
|
195
|
+
done.set!
|
196
|
+
end
|
197
|
+
|
198
|
+
def to_sexp
|
199
|
+
[:cvar, @name]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class ClassVariableAssignment < VariableAssignment
|
204
|
+
def bytecode(g)
|
205
|
+
pos(g)
|
206
|
+
|
207
|
+
if g.state.scope.module?
|
208
|
+
g.push :self
|
209
|
+
else
|
210
|
+
g.push_scope
|
211
|
+
end
|
212
|
+
|
213
|
+
if @value
|
214
|
+
g.push_literal @name
|
215
|
+
@value.bytecode(g)
|
216
|
+
else
|
217
|
+
g.swap
|
218
|
+
g.push_literal @name
|
219
|
+
g.swap
|
220
|
+
end
|
221
|
+
|
222
|
+
pos(g)
|
223
|
+
g.send :class_variable_set, 2
|
224
|
+
end
|
225
|
+
|
226
|
+
def sexp_name
|
227
|
+
:cvasgn
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class ClassVariableDeclaration < ClassVariableAssignment
|
232
|
+
def sexp_name
|
233
|
+
:cvdecl
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class CurrentException < Node
|
238
|
+
def bytecode(g)
|
239
|
+
pos(g)
|
240
|
+
g.push_current_exception
|
241
|
+
end
|
242
|
+
|
243
|
+
def defined(g)
|
244
|
+
g.push_literal "global-variable"
|
245
|
+
end
|
246
|
+
|
247
|
+
def to_sexp
|
248
|
+
[:gvar, :$!]
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
class GlobalVariableAccess < VariableAccess
|
253
|
+
EnglishBackrefs = {
|
254
|
+
:$LAST_MATCH_INFO => :~,
|
255
|
+
:$MATCH => :&,
|
256
|
+
:$PREMATCH => :'`',
|
257
|
+
:$POSTMATCH => :"'",
|
258
|
+
:$LAST_PAREN_MATCH => :+,
|
259
|
+
}
|
260
|
+
|
261
|
+
def self.for_name(line, name)
|
262
|
+
case name
|
263
|
+
when :$!
|
264
|
+
CurrentException.new(line)
|
265
|
+
when :$~
|
266
|
+
BackRef.new(line, :~)
|
267
|
+
else
|
268
|
+
if backref = EnglishBackrefs[name]
|
269
|
+
BackRef.new(line, backref)
|
270
|
+
else
|
271
|
+
new(line, name)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def bytecode(g)
|
277
|
+
pos(g)
|
278
|
+
|
279
|
+
g.push_rubinius
|
280
|
+
g.find_const :Globals
|
281
|
+
g.push_literal @name
|
282
|
+
g.send :[], 1
|
283
|
+
end
|
284
|
+
|
285
|
+
def variable_defined(g, f)
|
286
|
+
g.push_rubinius
|
287
|
+
g.find_const :Globals
|
288
|
+
g.push_literal @name
|
289
|
+
g.send :key?, 1
|
290
|
+
g.gif f
|
291
|
+
end
|
292
|
+
|
293
|
+
def defined(g)
|
294
|
+
f = g.new_label
|
295
|
+
done = g.new_label
|
296
|
+
|
297
|
+
variable_defined(g, f)
|
298
|
+
g.push_literal "global-variable"
|
299
|
+
g.goto done
|
300
|
+
|
301
|
+
f.set!
|
302
|
+
g.push :nil
|
303
|
+
|
304
|
+
done.set!
|
305
|
+
end
|
306
|
+
|
307
|
+
def to_sexp
|
308
|
+
[:gvar, @name]
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class GlobalVariableAssignment < VariableAssignment
|
313
|
+
def bytecode(g)
|
314
|
+
# @value can be nil if this is coming via an masgn, which means
|
315
|
+
# the value is already on the stack.
|
316
|
+
if @name == :$!
|
317
|
+
g.push_self
|
318
|
+
@value.bytecode(g) if @value
|
319
|
+
pos(g)
|
320
|
+
g.send :raise, 1, true
|
321
|
+
else
|
322
|
+
pos(g)
|
323
|
+
g.push_rubinius
|
324
|
+
g.find_const :Globals
|
325
|
+
if @value
|
326
|
+
g.push_literal @name
|
327
|
+
@value.bytecode(g)
|
328
|
+
else
|
329
|
+
g.swap
|
330
|
+
g.push_literal @name
|
331
|
+
g.swap
|
332
|
+
end
|
333
|
+
pos(g)
|
334
|
+
g.send :[]=, 2
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def sexp_name
|
339
|
+
:gasgn
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
class SplatAssignment < Node
|
344
|
+
attr_accessor :value
|
345
|
+
|
346
|
+
def initialize(line, value)
|
347
|
+
@line = line
|
348
|
+
@value = value
|
349
|
+
end
|
350
|
+
|
351
|
+
def bytecode(g)
|
352
|
+
pos(g)
|
353
|
+
|
354
|
+
g.cast_array
|
355
|
+
@value.bytecode(g)
|
356
|
+
end
|
357
|
+
|
358
|
+
def to_sexp
|
359
|
+
[:splat_assign, @value.to_sexp]
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
class SplatArray < SplatAssignment
|
364
|
+
def initialize(line, value, size)
|
365
|
+
@line = line
|
366
|
+
@value = value
|
367
|
+
@size = size
|
368
|
+
end
|
369
|
+
|
370
|
+
def bytecode(g)
|
371
|
+
pos(g)
|
372
|
+
|
373
|
+
g.make_array @size
|
374
|
+
|
375
|
+
@value.bytecode(g)
|
376
|
+
end
|
377
|
+
|
378
|
+
def to_sexp
|
379
|
+
[:splat, @value.to_sexp]
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
class SplatWrapped < SplatAssignment
|
384
|
+
def bytecode(g)
|
385
|
+
pos(g)
|
386
|
+
|
387
|
+
assign = g.new_label
|
388
|
+
|
389
|
+
g.dup
|
390
|
+
g.push_cpath_top
|
391
|
+
g.find_const :Array
|
392
|
+
g.swap
|
393
|
+
g.kind_of
|
394
|
+
g.git assign
|
395
|
+
g.make_array 1
|
396
|
+
|
397
|
+
assign.set!
|
398
|
+
@value.bytecode(g)
|
399
|
+
end
|
400
|
+
|
401
|
+
def to_sexp
|
402
|
+
[:splat, @value.to_sexp]
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
class EmptySplat < Node
|
407
|
+
def initialize(line, size)
|
408
|
+
@line = line
|
409
|
+
@size = size
|
410
|
+
end
|
411
|
+
|
412
|
+
def bytecode(g)
|
413
|
+
return if @size == 0
|
414
|
+
|
415
|
+
pos(g)
|
416
|
+
|
417
|
+
g.make_array @size
|
418
|
+
end
|
419
|
+
|
420
|
+
def to_sexp
|
421
|
+
[:splat]
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
class InstanceVariableAccess < VariableAccess
|
426
|
+
def bytecode(g)
|
427
|
+
pos(g)
|
428
|
+
|
429
|
+
g.push_ivar @name
|
430
|
+
end
|
431
|
+
|
432
|
+
def variable_defined(g, f)
|
433
|
+
g.push :self
|
434
|
+
g.push_literal @name
|
435
|
+
g.send :__instance_variable_defined_p__, 1
|
436
|
+
g.gif f
|
437
|
+
end
|
438
|
+
|
439
|
+
def defined(g)
|
440
|
+
f = g.new_label
|
441
|
+
done = g.new_label
|
442
|
+
|
443
|
+
variable_defined(g, f)
|
444
|
+
g.push_literal "instance-variable"
|
445
|
+
g.goto done
|
446
|
+
|
447
|
+
f.set!
|
448
|
+
g.push :nil
|
449
|
+
|
450
|
+
done.set!
|
451
|
+
end
|
452
|
+
|
453
|
+
def to_sexp
|
454
|
+
[:ivar, @name]
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
class InstanceVariableAssignment < VariableAssignment
|
459
|
+
def bytecode(g)
|
460
|
+
@value.bytecode(g) if @value
|
461
|
+
|
462
|
+
pos(g)
|
463
|
+
g.set_ivar @name
|
464
|
+
end
|
465
|
+
|
466
|
+
def sexp_name
|
467
|
+
:iasgn
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
class LocalVariableAccess < VariableAccess
|
472
|
+
include LocalVariable
|
473
|
+
|
474
|
+
def initialize(line, name)
|
475
|
+
@line = line
|
476
|
+
@name = name
|
477
|
+
@variable = nil
|
478
|
+
end
|
479
|
+
|
480
|
+
def bytecode(g)
|
481
|
+
pos(g)
|
482
|
+
|
483
|
+
unless @variable
|
484
|
+
g.state.scope.assign_local_reference self
|
485
|
+
end
|
486
|
+
@variable.get_bytecode(g)
|
487
|
+
end
|
488
|
+
|
489
|
+
def defined(g)
|
490
|
+
g.push_literal "local-variable"
|
491
|
+
end
|
492
|
+
|
493
|
+
def value_defined(g, f)
|
494
|
+
bytecode(g)
|
495
|
+
end
|
496
|
+
|
497
|
+
def to_sexp
|
498
|
+
[:lvar, @name]
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
class LocalVariableAssignment < VariableAssignment
|
503
|
+
include LocalVariable
|
504
|
+
|
505
|
+
def initialize(line, name, value)
|
506
|
+
@line = line
|
507
|
+
@name = name
|
508
|
+
@value = value
|
509
|
+
@variable = nil
|
510
|
+
end
|
511
|
+
|
512
|
+
def bytecode(g)
|
513
|
+
unless @variable
|
514
|
+
g.state.scope.assign_local_reference self
|
515
|
+
end
|
516
|
+
|
517
|
+
if @value
|
518
|
+
@value.bytecode(g)
|
519
|
+
end
|
520
|
+
|
521
|
+
# Set the position after the value, so the position
|
522
|
+
# reflects where the assignment itself is done
|
523
|
+
pos(g)
|
524
|
+
|
525
|
+
@variable.set_bytecode(g)
|
526
|
+
end
|
527
|
+
|
528
|
+
def sexp_name
|
529
|
+
:lasgn
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
class PostArg < Node
|
534
|
+
attr_accessor :into, :rest
|
535
|
+
|
536
|
+
def initialize(line, into, rest)
|
537
|
+
@line = line
|
538
|
+
@into = into
|
539
|
+
@rest = rest
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
class MultipleAssignment < Node
|
544
|
+
attr_accessor :left, :right, :splat, :block, :post
|
545
|
+
|
546
|
+
def initialize(line, left, right, splat)
|
547
|
+
@line = line
|
548
|
+
@left = left
|
549
|
+
@right = right
|
550
|
+
@splat = nil
|
551
|
+
@block = nil # support for |&b|
|
552
|
+
@post = nil # in `a,*b,c`, c is in post.
|
553
|
+
|
554
|
+
@fixed = right.kind_of?(ArrayLiteral) ? true : false
|
555
|
+
|
556
|
+
if splat.kind_of? Node
|
557
|
+
if @left
|
558
|
+
if right
|
559
|
+
@splat = SplatAssignment.new line, splat
|
560
|
+
else
|
561
|
+
@splat = SplatWrapped.new line, splat
|
562
|
+
end
|
563
|
+
elsif @fixed
|
564
|
+
@splat = SplatArray.new line, splat, right.body.size
|
565
|
+
elsif right.kind_of? SplatValue
|
566
|
+
@splat = splat
|
567
|
+
else
|
568
|
+
@splat = SplatWrapped.new line, splat
|
569
|
+
end
|
570
|
+
elsif splat
|
571
|
+
# We need a node for eg { |*| } and { |a, *| }
|
572
|
+
size = @fixed ? right.body.size : 0
|
573
|
+
@splat = EmptySplat.new line, size
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
def pad_short(g)
|
578
|
+
short = @left.body.size - @right.body.size
|
579
|
+
if short > 0
|
580
|
+
short.times { g.push :nil }
|
581
|
+
g.make_array 0 if @splat
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
def pop_excess(g)
|
586
|
+
excess = @right.body.size - @left.body.size
|
587
|
+
excess.times { g.pop } if excess > 0
|
588
|
+
end
|
589
|
+
|
590
|
+
def make_array(g)
|
591
|
+
size = @right.body.size - @left.body.size
|
592
|
+
g.make_array size if size >= 0
|
593
|
+
end
|
594
|
+
|
595
|
+
def make_retval(g)
|
596
|
+
size = @right.body.size
|
597
|
+
if @left and !@splat
|
598
|
+
lhs = @left.body.size
|
599
|
+
size = lhs if lhs > size
|
600
|
+
end
|
601
|
+
g.dup_many @right.body.size
|
602
|
+
g.make_array @right.body.size
|
603
|
+
g.move_down size
|
604
|
+
end
|
605
|
+
|
606
|
+
def rotate(g)
|
607
|
+
if @splat
|
608
|
+
size = @left.body.size + 1
|
609
|
+
else
|
610
|
+
size = @right.body.size
|
611
|
+
end
|
612
|
+
g.rotate size
|
613
|
+
end
|
614
|
+
|
615
|
+
def iter_arguments
|
616
|
+
@iter_arguments = true
|
617
|
+
end
|
618
|
+
|
619
|
+
def declare_local_scope(scope)
|
620
|
+
# Fix the scope for locals introduced by the left. We
|
621
|
+
# do this before running the code for the right so that
|
622
|
+
# right side sees the proper scoping of the locals on the left.
|
623
|
+
|
624
|
+
if @left
|
625
|
+
@left.body.each do |var|
|
626
|
+
case var
|
627
|
+
when LocalVariable
|
628
|
+
scope.assign_local_reference var
|
629
|
+
when MultipleAssignment
|
630
|
+
var.declare_local_scope(scope)
|
631
|
+
end
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
if @splat and @splat.kind_of?(SplatAssignment)
|
636
|
+
if @splat.value.kind_of?(LocalVariable)
|
637
|
+
scope.assign_local_reference @splat.value
|
638
|
+
end
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def bytecode(g, array_on_stack=false)
|
643
|
+
unless array_on_stack
|
644
|
+
g.cast_array unless @right or (@splat and not @left)
|
645
|
+
end
|
646
|
+
|
647
|
+
declare_local_scope(g.state.scope)
|
648
|
+
|
649
|
+
if @fixed
|
650
|
+
pad_short(g) if @left and !@splat
|
651
|
+
@right.body.each { |x| x.bytecode(g) }
|
652
|
+
|
653
|
+
if @left
|
654
|
+
make_retval(g)
|
655
|
+
|
656
|
+
if @splat
|
657
|
+
pad_short(g)
|
658
|
+
make_array(g)
|
659
|
+
end
|
660
|
+
|
661
|
+
rotate(g)
|
662
|
+
|
663
|
+
g.state.push_masgn
|
664
|
+
@left.body.each do |x|
|
665
|
+
x.bytecode(g)
|
666
|
+
g.pop
|
667
|
+
end
|
668
|
+
g.state.pop_masgn
|
669
|
+
|
670
|
+
pop_excess(g) unless @splat
|
671
|
+
end
|
672
|
+
else
|
673
|
+
if @right
|
674
|
+
if @right.kind_of? ArrayLiteral and @right.body.size == 1
|
675
|
+
@right.body.first.bytecode(g)
|
676
|
+
g.cast_multi_value
|
677
|
+
else
|
678
|
+
@right.bytecode(g)
|
679
|
+
end
|
680
|
+
|
681
|
+
g.cast_array unless @right.kind_of? ToArray
|
682
|
+
g.dup # Use the array as the return value
|
683
|
+
end
|
684
|
+
|
685
|
+
if @left
|
686
|
+
g.state.push_masgn
|
687
|
+
@left.body.each do |x|
|
688
|
+
g.shift_array
|
689
|
+
g.cast_array if x.kind_of? MultipleAssignment and x.left
|
690
|
+
x.bytecode(g)
|
691
|
+
g.pop
|
692
|
+
end
|
693
|
+
g.state.pop_masgn
|
694
|
+
end
|
695
|
+
|
696
|
+
if @post
|
697
|
+
g.state.push_masgn
|
698
|
+
@post.body.each do |x|
|
699
|
+
g.dup
|
700
|
+
g.send :pop, 0
|
701
|
+
g.cast_array if x.kind_of? MultipleAssignment and x.left
|
702
|
+
x.bytecode(g)
|
703
|
+
g.pop
|
704
|
+
end
|
705
|
+
g.state.pop_masgn
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
if @splat
|
710
|
+
g.state.push_masgn
|
711
|
+
@splat.bytecode(g)
|
712
|
+
|
713
|
+
# Use the array as the return value
|
714
|
+
g.dup if @fixed and !@left
|
715
|
+
|
716
|
+
g.state.pop_masgn
|
717
|
+
end
|
718
|
+
|
719
|
+
g.pop if @right and (!@fixed or @splat)
|
720
|
+
end
|
721
|
+
|
722
|
+
def defined(g)
|
723
|
+
g.push_literal "assignment"
|
724
|
+
end
|
725
|
+
|
726
|
+
def to_sexp
|
727
|
+
left = @left ? @left.to_sexp : [:array]
|
728
|
+
left << [:splat, @splat.to_sexp] if @splat
|
729
|
+
left << @block.to_sexp if @block
|
730
|
+
|
731
|
+
sexp = [:masgn, left]
|
732
|
+
sexp << @right.to_sexp if @right
|
733
|
+
sexp
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
class LeftPatternVariable < Node
|
738
|
+
include LocalVariable
|
739
|
+
|
740
|
+
attr_accessor :name, :value
|
741
|
+
|
742
|
+
def initialize(line, name)
|
743
|
+
@line = line
|
744
|
+
@name = name
|
745
|
+
@variable = nil
|
746
|
+
end
|
747
|
+
|
748
|
+
def position_bytecode(g)
|
749
|
+
@variable.get_bytecode(g)
|
750
|
+
g.cast_array
|
751
|
+
end
|
752
|
+
|
753
|
+
def bytecode(g)
|
754
|
+
pos(g)
|
755
|
+
|
756
|
+
unless @variable
|
757
|
+
g.state.scope.assign_local_reference self
|
758
|
+
end
|
759
|
+
|
760
|
+
g.shift_array
|
761
|
+
@variable.set_bytecode(g)
|
762
|
+
g.pop
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
class SplatPatternVariable < Node
|
767
|
+
include LocalVariable
|
768
|
+
|
769
|
+
attr_accessor :name, :value
|
770
|
+
|
771
|
+
def initialize(line, name)
|
772
|
+
@line = line
|
773
|
+
@name = name
|
774
|
+
@variable = nil
|
775
|
+
end
|
776
|
+
|
777
|
+
def position_bytecode(g)
|
778
|
+
@variable.get_bytecode(g)
|
779
|
+
g.cast_array
|
780
|
+
end
|
781
|
+
|
782
|
+
def bytecode(g)
|
783
|
+
pos(g)
|
784
|
+
|
785
|
+
unless @variable
|
786
|
+
g.state.scope.assign_local_reference self
|
787
|
+
end
|
788
|
+
|
789
|
+
g.dup
|
790
|
+
@variable.set_bytecode(g)
|
791
|
+
g.pop
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
class PostPatternVariable < Node
|
796
|
+
include LocalVariable
|
797
|
+
|
798
|
+
attr_accessor :name, :value
|
799
|
+
|
800
|
+
def initialize(line, name, idx)
|
801
|
+
@line = line
|
802
|
+
@name = name
|
803
|
+
@pos = idx
|
804
|
+
@variable = nil
|
805
|
+
end
|
806
|
+
|
807
|
+
def position_bytecode(g)
|
808
|
+
@variable.get_bytecode(g)
|
809
|
+
g.cast_array
|
810
|
+
end
|
811
|
+
|
812
|
+
def bytecode(g)
|
813
|
+
pos(g)
|
814
|
+
|
815
|
+
unless @variable
|
816
|
+
g.state.scope.assign_local_reference self
|
817
|
+
end
|
818
|
+
|
819
|
+
too_big = g.new_label
|
820
|
+
done = g.new_label
|
821
|
+
|
822
|
+
g.dup
|
823
|
+
g.send :size, 0
|
824
|
+
g.push_int @pos
|
825
|
+
g.send :>, 1
|
826
|
+
g.gif too_big
|
827
|
+
g.dup
|
828
|
+
g.send :pop, 0
|
829
|
+
|
830
|
+
g.goto done
|
831
|
+
too_big.set!
|
832
|
+
g.push_nil
|
833
|
+
@variable.set_bytecode(g)
|
834
|
+
g.goto done
|
835
|
+
|
836
|
+
done.set!
|
837
|
+
@variable.set_bytecode(g)
|
838
|
+
g.pop
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
end
|