rubinius-ast 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 813fe60589de3d0cb89d69641cbc57f5141d8a59
4
+ data.tar.gz: 3115c03413ae9350818dffbccd915bb37230d0f9
5
+ SHA512:
6
+ metadata.gz: 19aacbcff956617afb4c139d2b8e9cbe232a1b4f0d2ff9e9a3a6a55b2ffbe83bd920a6ee99ba7dfeaa987fc6160a3a243bd6addcac6c8913fb0fafc9a2c49b6a
7
+ data.tar.gz: 829c797ed156b13791c5e0746b451172d5c356ea163d3a97085b3f8018028a5dd689d9591546392ae135004c86cfe1232c8c7087cc33f0935f7953c873d49878
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubinius-ast.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubinius::Ast
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubinius-ast'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubinius-ast
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,324 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+
6
+ class TypeConstant < Node
7
+ def initialize(line)
8
+ @line = line
9
+ end
10
+
11
+ def bytecode(g)
12
+ pos(g)
13
+ g.push_type
14
+ end
15
+ end
16
+
17
+ class MirrorConstant < Node
18
+ def initialize(line)
19
+ @line = line
20
+ end
21
+
22
+ def bytecode(g)
23
+ pos(g)
24
+ g.push_mirror
25
+ end
26
+ end
27
+
28
+ class ScopedConstant < Node
29
+ attr_accessor :parent, :name
30
+
31
+ def initialize(line, parent, name)
32
+ @line = line
33
+ @parent = parent
34
+ @name = name
35
+ end
36
+
37
+ def bytecode(g)
38
+ pos(g)
39
+
40
+ @parent.bytecode(g)
41
+ g.find_const @name
42
+ end
43
+
44
+ def assign_bytecode(g, value)
45
+ pos(g)
46
+
47
+ value.bytecode(g)
48
+ g.push_literal @name
49
+ @parent.bytecode(g)
50
+ g.rotate 3
51
+ end
52
+
53
+ def masgn_bytecode(g)
54
+ pos(g)
55
+
56
+ @parent.bytecode(g)
57
+ g.swap
58
+ g.push_literal @name
59
+ end
60
+
61
+ def defined(g)
62
+ f = g.new_label
63
+ done = g.new_label
64
+
65
+ value_defined(g, f, false)
66
+
67
+ g.pop
68
+ g.push_literal "constant"
69
+ g.goto done
70
+
71
+ f.set!
72
+ g.push :nil
73
+
74
+ done.set!
75
+ end
76
+
77
+ def value_defined(g, f, const_missing=true)
78
+ # Save the current exception into a stack local
79
+ g.push_exception_state
80
+ outer_exc_state = g.new_stack_local
81
+ g.set_stack_local outer_exc_state
82
+ g.pop
83
+
84
+ ex = g.new_label
85
+ ok = g.new_label
86
+ g.setup_unwind ex, RescueType
87
+
88
+ @parent.bytecode(g)
89
+ g.push_literal @name
90
+ g.push(const_missing ? :true : :false)
91
+ g.invoke_primitive :vm_const_defined_under, 3
92
+
93
+ g.pop_unwind
94
+ g.goto ok
95
+
96
+ ex.set!
97
+ g.clear_exception
98
+ g.push_stack_local outer_exc_state
99
+ g.restore_exception_state
100
+ g.goto f
101
+
102
+ ok.set!
103
+ end
104
+
105
+ def to_sexp
106
+ [:colon2, @parent.to_sexp, @name]
107
+ end
108
+
109
+ alias_method :assign_sexp, :to_sexp
110
+ end
111
+
112
+ class ToplevelConstant < Node
113
+ attr_accessor :name
114
+
115
+ def initialize(line, name)
116
+ @line = line
117
+ @name = name
118
+ end
119
+
120
+ def bytecode(g)
121
+ pos(g)
122
+
123
+ g.push_cpath_top
124
+ g.find_const @name
125
+ end
126
+
127
+ def assign_bytecode(g, value)
128
+ pos(g)
129
+
130
+ g.push_cpath_top
131
+ g.push_literal @name
132
+ value.bytecode(g)
133
+ end
134
+
135
+ def masgn_bytecode(g)
136
+ pos(g)
137
+
138
+ g.push_cpath_top
139
+ g.swap
140
+ g.push_literal @name
141
+ end
142
+
143
+ def defined(g)
144
+ f = g.new_label
145
+ done = g.new_label
146
+
147
+ value_defined(g, f)
148
+
149
+ g.pop
150
+ g.push_literal "constant"
151
+ g.goto done
152
+
153
+ f.set!
154
+ g.push :nil
155
+
156
+ done.set!
157
+ end
158
+
159
+ def value_defined(g, f)
160
+ # Save the current exception into a stack local
161
+ g.push_exception_state
162
+ outer_exc_state = g.new_stack_local
163
+ g.set_stack_local outer_exc_state
164
+ g.pop
165
+
166
+ ex = g.new_label
167
+ ok = g.new_label
168
+ g.setup_unwind ex, RescueType
169
+
170
+ g.push_cpath_top
171
+ g.push_literal @name
172
+ g.push :false
173
+ g.invoke_primitive :vm_const_defined_under, 3
174
+
175
+ g.pop_unwind
176
+ g.goto ok
177
+
178
+ ex.set!
179
+ g.clear_exception
180
+ g.push_stack_local outer_exc_state
181
+ g.restore_exception_state
182
+ g.goto f
183
+
184
+ ok.set!
185
+ end
186
+
187
+ def to_sexp
188
+ [:colon3, @name]
189
+ end
190
+
191
+ alias_method :assign_sexp, :to_sexp
192
+ end
193
+
194
+ class ConstantAccess < Node
195
+ attr_accessor :name
196
+
197
+ def initialize(line, name, top_level = false)
198
+ @line = line
199
+ @name = name
200
+ @top_level = top_level
201
+ end
202
+
203
+ def bytecode(g)
204
+ pos(g)
205
+
206
+ if g.state.op_asgn?
207
+ g.push_literal Compiler::Runtime
208
+ g.push_literal @name
209
+ g.push_scope
210
+ g.send :find_constant_for_op_asign_or, 2
211
+ else
212
+ if @top_level
213
+ g.push_cpath_top
214
+ g.find_const @name
215
+ else
216
+ g.push_const @name
217
+ end
218
+ end
219
+ end
220
+
221
+ def assign_bytecode(g, value)
222
+ pos(g)
223
+
224
+ g.push_scope
225
+ g.push_literal @name
226
+ value.bytecode(g)
227
+ end
228
+
229
+ def masgn_bytecode(g)
230
+ pos(g)
231
+
232
+ g.push_scope
233
+ g.swap
234
+ g.push_literal @name
235
+ end
236
+
237
+ def defined(g)
238
+ f = g.new_label
239
+ done = g.new_label
240
+
241
+ value_defined(g, f)
242
+
243
+ g.pop
244
+ g.push_literal "constant"
245
+ g.goto done
246
+
247
+ f.set!
248
+ g.push :nil
249
+
250
+ done.set!
251
+ end
252
+
253
+ def value_defined(g, f)
254
+ # Save the current exception into a stack local
255
+ g.push_exception_state
256
+ outer_exc_state = g.new_stack_local
257
+ g.set_stack_local outer_exc_state
258
+ g.pop
259
+
260
+ ex = g.new_label
261
+ ok = g.new_label
262
+ g.setup_unwind ex, RescueType
263
+
264
+ g.push_literal @name
265
+ g.invoke_primitive :vm_const_defined, 1
266
+
267
+ g.pop_unwind
268
+ g.goto ok
269
+
270
+ ex.set!
271
+ g.clear_exception
272
+ g.push_stack_local outer_exc_state
273
+ g.restore_exception_state
274
+ g.goto f
275
+
276
+ ok.set!
277
+ end
278
+
279
+ def assign_sexp
280
+ @name
281
+ end
282
+
283
+ def to_sexp
284
+ [:const, @name]
285
+ end
286
+ end
287
+
288
+ class ConstantAssignment < Node
289
+ attr_accessor :constant, :value
290
+
291
+ def initialize(line, expr, value)
292
+ @line = line
293
+ @value = value
294
+
295
+ if expr.kind_of? Symbol
296
+ @constant = ConstantAccess.new line, expr
297
+ else
298
+ @constant = expr
299
+ end
300
+ end
301
+
302
+ def masgn_bytecode(g)
303
+ @constant.masgn_bytecode(g)
304
+ g.swap
305
+ g.send :const_set, 2
306
+ end
307
+
308
+ def bytecode(g)
309
+ pos(g)
310
+
311
+ return masgn_bytecode(g) if g.state.masgn?
312
+
313
+ @constant.assign_bytecode(g, @value)
314
+ g.send :const_set, 2
315
+ end
316
+
317
+ def to_sexp
318
+ sexp = [:cdecl, @constant.assign_sexp]
319
+ sexp << @value.to_sexp if @value
320
+ sexp
321
+ end
322
+ end
323
+ end
324
+ end
@@ -0,0 +1,698 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class Case < Node
6
+ attr_accessor :whens, :else
7
+
8
+ def initialize(line, whens, else_body)
9
+ @line = line
10
+ @whens = whens
11
+ @else = else_body || NilLiteral.new(line)
12
+ end
13
+
14
+ def bytecode(g)
15
+ pos(g)
16
+
17
+ done = g.new_label
18
+
19
+ @whens.each do |w|
20
+ w.bytecode(g, done)
21
+ end
22
+
23
+ @else.bytecode(g)
24
+
25
+ # See command in if about why using line 0
26
+ g.set_line 0
27
+
28
+ done.set!
29
+ end
30
+
31
+ def receiver_sexp
32
+ nil
33
+ end
34
+
35
+ def to_sexp
36
+ else_sexp = @else.kind_of?(NilLiteral) ? nil : @else.to_sexp
37
+ sexp = [:case, receiver_sexp]
38
+ sexp << [:whens] + @whens.map { |x| x.to_sexp }
39
+ sexp << else_sexp
40
+ sexp
41
+ end
42
+ end
43
+
44
+ class ReceiverCase < Case
45
+ attr_accessor :receiver
46
+
47
+ def initialize(line, receiver, whens, else_body)
48
+ @line = line
49
+ @receiver = receiver
50
+ @whens = whens
51
+ @else = else_body || NilLiteral.new(line)
52
+ end
53
+
54
+ def bytecode(g)
55
+ pos(g)
56
+
57
+ done = g.new_label
58
+
59
+ @receiver.bytecode(g)
60
+
61
+ @whens.each do |w|
62
+ w.receiver_bytecode(g, done)
63
+ end
64
+
65
+ g.pop
66
+ @else.bytecode(g)
67
+
68
+ # See command in if about why using line 0
69
+ g.set_line 0
70
+
71
+ done.set!
72
+ end
73
+
74
+ def receiver_sexp
75
+ @receiver.to_sexp
76
+ end
77
+ end
78
+
79
+ class When < Node
80
+ attr_accessor :conditions, :body, :single, :splat
81
+
82
+ def initialize(line, conditions, body)
83
+ @line = line
84
+ @body = body || NilLiteral.new(line)
85
+ @splat = nil
86
+ @single = nil
87
+
88
+ if conditions.kind_of? ConcatArgs
89
+ @splat = SplatWhen.new line, conditions.rest
90
+ conditions = conditions.array
91
+ end
92
+
93
+ if conditions.kind_of? ArrayLiteral
94
+ if conditions.body.last.kind_of? When
95
+ last = conditions.body.pop
96
+ if last.conditions.kind_of? ArrayLiteral
97
+ conditions.body.concat last.conditions.body
98
+ elsif last.single
99
+ @splat = SplatWhen.new line, last.single
100
+ else
101
+ @splat = SplatWhen.new line, last.conditions
102
+ end
103
+ end
104
+
105
+ if conditions.body.size == 1 and !@splat
106
+ @single = conditions.body.first
107
+ else
108
+ @conditions = conditions
109
+ end
110
+ elsif conditions.kind_of? SplatValue
111
+ @splat = SplatWhen.new line, conditions.value
112
+ @conditions = nil
113
+ else
114
+ @conditions = conditions
115
+ end
116
+ end
117
+
118
+ def condition_bytecode(g, condition)
119
+ condition.pos(g)
120
+ g.dup
121
+ condition.bytecode(g)
122
+ g.swap
123
+ g.send :===, 1
124
+ end
125
+
126
+ def receiver_bytecode(g, done)
127
+ body = g.new_label
128
+ nxt = g.new_label
129
+
130
+ if @single
131
+ condition_bytecode(g, @single)
132
+ g.gif nxt
133
+ else
134
+ if @conditions
135
+ @conditions.body.each do |c|
136
+ condition_bytecode(g, c)
137
+ g.git body
138
+ end
139
+ end
140
+
141
+ @splat.receiver_bytecode(g, body, nxt) if @splat
142
+ g.goto nxt
143
+
144
+ body.set!
145
+ end
146
+
147
+ g.pop
148
+ @body.bytecode(g)
149
+ g.goto done
150
+
151
+ nxt.set!
152
+ end
153
+
154
+ def bytecode(g, done)
155
+ pos(g)
156
+
157
+ nxt = g.new_label
158
+ body = g.new_label
159
+
160
+ if @single
161
+ @single.bytecode(g)
162
+ g.gif nxt
163
+ else
164
+ if @conditions
165
+ @conditions.body.each do |condition|
166
+ condition.bytecode(g)
167
+ g.git body
168
+ end
169
+ end
170
+
171
+ @splat.bytecode(g, body, nxt) if @splat
172
+ g.goto nxt
173
+
174
+ body.set!
175
+ end
176
+
177
+ @body.bytecode(g)
178
+ g.goto done
179
+
180
+ nxt.set!
181
+ end
182
+
183
+ def to_sexp
184
+ if @single
185
+ conditions_sexp = [:array, @single.to_sexp]
186
+ else
187
+ conditions_sexp = @conditions ? @conditions.to_sexp : []
188
+ conditions_sexp << @splat.to_sexp if @splat
189
+ end
190
+ [:when, conditions_sexp, @body.to_sexp]
191
+ end
192
+ end
193
+
194
+ class SplatWhen < Node
195
+ attr_accessor :condition
196
+
197
+ def initialize(line, condition)
198
+ @line = line
199
+ @condition = condition
200
+ end
201
+
202
+ def receiver_bytecode(g, body, nxt)
203
+ pos(g)
204
+
205
+ g.dup
206
+ @condition.bytecode(g)
207
+ g.cast_array
208
+ g.push_literal Compiler::Runtime
209
+ g.rotate(3)
210
+ g.send :matches_when, 2
211
+ g.git body
212
+ end
213
+
214
+ def bytecode(g, body, nxt)
215
+ # TODO: why is this empty?
216
+ end
217
+
218
+ def to_sexp
219
+ [:when, @condition.to_sexp, nil]
220
+ end
221
+ end
222
+
223
+ class Flip2 < Node
224
+ def initialize(line, start, finish)
225
+ @line = line
226
+ @start = start
227
+ @finish = finish
228
+ end
229
+
230
+ def sexp_name
231
+ :flip2
232
+ end
233
+
234
+ def exclusive?
235
+ false
236
+ end
237
+
238
+ def bytecode(g)
239
+ done = g.new_label
240
+ on_label = g.new_label
241
+ index = g.state.flip_flops
242
+ g.state.push_flip_flop
243
+
244
+ get_flip_flop(g, index)
245
+ g.git on_label
246
+
247
+ @start.bytecode(g)
248
+ g.dup
249
+ g.gif done
250
+ g.pop
251
+ set_flip_flop(g, index, true)
252
+
253
+ if exclusive?
254
+ g.goto done
255
+ else
256
+ g.pop
257
+ end
258
+
259
+ on_label.set!
260
+ g.push_literal true
261
+ @finish.bytecode(g)
262
+ g.gif done
263
+ set_flip_flop(g, index, false)
264
+ g.pop
265
+
266
+ done.set!
267
+ end
268
+
269
+ def get_flip_flop(g, index)
270
+ g.push_literal Compiler::Runtime
271
+ g.push_scope
272
+ g.push_literal index
273
+ g.send(:get_flip_flop, 2)
274
+ end
275
+
276
+ def set_flip_flop(g, index, value)
277
+ g.push_literal Compiler::Runtime
278
+ g.push_scope
279
+ g.push_literal index
280
+ g.push_literal value
281
+ g.send(:set_flip_flop, 3)
282
+ end
283
+
284
+ def to_sexp
285
+ [sexp_name, @start.to_sexp, @finish.to_sexp]
286
+ end
287
+ end
288
+
289
+ class Flip3 < Flip2
290
+ def sexp_name
291
+ :flip3
292
+ end
293
+
294
+ def exclusive?
295
+ true
296
+ end
297
+ end
298
+
299
+ class If < Node
300
+ attr_accessor :condition, :body, :else
301
+
302
+ def initialize(line, condition, body, else_body)
303
+ @line = line
304
+ @condition = condition
305
+ @body = body || NilLiteral.new(line)
306
+ @else = else_body || NilLiteral.new(line)
307
+ end
308
+
309
+ def bytecode(g)
310
+ pos(g)
311
+
312
+ done = g.new_label
313
+ else_label = g.new_label
314
+
315
+ @condition.bytecode(g)
316
+ g.gif else_label
317
+
318
+ @body.bytecode(g)
319
+ g.goto done
320
+
321
+ else_label.set!
322
+ @else.bytecode(g)
323
+
324
+ # Use line 0 to indicate "compiler generated code"
325
+ # so that debuggers and such don't get confused by
326
+ # thinking the then branch jumps into the else branch.
327
+ g.set_line 0
328
+ done.set!
329
+ end
330
+
331
+ def to_sexp
332
+ else_sexp = @else.kind_of?(NilLiteral) ? nil : @else.to_sexp
333
+ [:if, @condition.to_sexp, @body.to_sexp, else_sexp]
334
+ end
335
+ end
336
+
337
+ class While < Node
338
+ attr_accessor :condition, :body, :check_first
339
+
340
+ def initialize(line, condition, body, check_first)
341
+ @line = line
342
+ @condition = condition
343
+ @body = body || NilLiteral.new(line)
344
+ @check_first = check_first
345
+ end
346
+
347
+ def condition_bytecode(g, bottom, use_gif)
348
+ @condition.bytecode(g)
349
+ if use_gif
350
+ g.gif bottom
351
+ else
352
+ g.git bottom
353
+ end
354
+ end
355
+
356
+ def body_bytecode(g, lbl)
357
+ g.state.push_loop
358
+ @body.bytecode(g)
359
+ g.state.pop_loop
360
+
361
+ # This is a loop epilogue. Nothing that changes
362
+ # computation should be put here.
363
+ lbl.set!
364
+ g.pop
365
+ g.check_interrupts
366
+ end
367
+
368
+ def bytecode(g, use_gif=true)
369
+ pos(g)
370
+
371
+ g.push_modifiers
372
+
373
+ top = g.new_label
374
+ post = g.next = g.new_label
375
+ bottom = g.new_label
376
+
377
+ g.break = g.new_label
378
+
379
+ if @check_first
380
+ g.redo = g.new_label
381
+
382
+ top.set!
383
+ condition_bytecode(g, bottom, use_gif)
384
+
385
+ g.redo.set!
386
+ body_bytecode(g, post)
387
+ else
388
+ g.redo = top
389
+
390
+ top.set!
391
+ body_bytecode(g, post)
392
+
393
+ condition_bytecode(g, bottom, use_gif)
394
+ end
395
+
396
+ g.goto top
397
+
398
+ # See other set_line(0) comments
399
+ g.set_line 0
400
+
401
+ bottom.set!
402
+ g.push :nil
403
+ g.break.set!
404
+
405
+ g.pop_modifiers
406
+ end
407
+
408
+ def sexp_name
409
+ :while
410
+ end
411
+
412
+ def to_sexp
413
+ [sexp_name, @condition.to_sexp, @body.to_sexp, @check_first]
414
+ end
415
+ end
416
+
417
+ class Until < While
418
+ def bytecode(g)
419
+ super(g, false)
420
+ end
421
+
422
+ def sexp_name
423
+ :until
424
+ end
425
+ end
426
+
427
+ class Match < Node
428
+ attr_accessor :pattern
429
+
430
+ def initialize(line, pattern, flags)
431
+ @line = line
432
+ @pattern = RegexLiteral.new line, pattern, flags
433
+ end
434
+
435
+ def bytecode(g)
436
+ pos(g)
437
+
438
+ g.push_rubinius
439
+ g.find_const :Globals
440
+ g.push_literal :$_
441
+ g.send :[], 1
442
+
443
+ @pattern.bytecode(g)
444
+
445
+ g.send :=~, 1
446
+ end
447
+
448
+ def to_sexp
449
+ [:match, @pattern.to_sexp]
450
+ end
451
+ end
452
+
453
+ class Match2 < Node
454
+ attr_accessor :pattern, :value
455
+
456
+ def initialize(line, pattern, value)
457
+ @line = line
458
+ @pattern = pattern
459
+ @value = value
460
+ end
461
+
462
+ def bytecode(g)
463
+ pos(g)
464
+
465
+ @pattern.bytecode(g)
466
+ @value.bytecode(g)
467
+ g.send :=~, 1
468
+ if @pattern.kind_of? RegexLiteral
469
+ regexp = Regexp.new(@pattern.source)
470
+ # TODO: this code cannot just use Rubinius-specific methods.
471
+ # Fix without using respond_to?.
472
+ if regexp.respond_to? :name_table
473
+ if table = regexp.name_table
474
+ table.sort_by { |name, idx| idx }.each do |name, idx|
475
+ local = g.state.scope.new_local name
476
+ g.last_match 5, idx.last - 1
477
+
478
+ case local
479
+ when Compiler::LocalVariable
480
+ g.set_local local.slot
481
+ when Compiler::EvalLocalVariable
482
+ g.push_variables
483
+ g.swap
484
+ g.push_literal name
485
+ g.swap
486
+ g.send :set_eval_local, 2, false
487
+ else
488
+ raise CompileError, "unknown type of local #{local.inspect}"
489
+ end
490
+
491
+ g.pop
492
+ end
493
+ end
494
+ end
495
+ end
496
+ end
497
+
498
+ def to_sexp
499
+ [:match2, @pattern.to_sexp, @value.to_sexp]
500
+ end
501
+ end
502
+
503
+ class Match3 < Node
504
+ attr_accessor :pattern, :value
505
+
506
+ def initialize(line, pattern, value)
507
+ @line = line
508
+ @pattern = pattern
509
+ @value = value
510
+ end
511
+
512
+ def bytecode(g)
513
+ pos(g)
514
+
515
+ @value.bytecode(g)
516
+ @pattern.bytecode(g)
517
+ g.send :=~, 1
518
+ end
519
+
520
+ def to_sexp
521
+ [:match3, @pattern.to_sexp, @value.to_sexp]
522
+ end
523
+ end
524
+
525
+ class Break < Node
526
+ attr_accessor :value
527
+
528
+ def initialize(line, expr)
529
+ @line = line
530
+ @value = expr || NilLiteral.new(line)
531
+ end
532
+
533
+ def jump_error(g, name)
534
+ g.push_rubinius
535
+ g.push_literal name
536
+ g.send :jump_error, 1
537
+ end
538
+
539
+ def bytecode(g)
540
+ pos(g)
541
+
542
+ @value.bytecode(g)
543
+
544
+ if g.break
545
+ g.goto g.break
546
+ elsif g.state.block?
547
+ g.raise_break
548
+ else
549
+ g.pop
550
+ jump_error g, :break
551
+ end
552
+ end
553
+
554
+ def sexp_name
555
+ :break
556
+ end
557
+
558
+ def to_sexp
559
+ sexp = [sexp_name]
560
+ sexp << @value.to_sexp if @value
561
+ sexp
562
+ end
563
+ end
564
+
565
+ class Next < Break
566
+ def initialize(line, value)
567
+ @line = line
568
+ @value = value
569
+ end
570
+
571
+ def bytecode(g)
572
+ pos(g)
573
+
574
+ # From "The Ruby Programming Lanuage"
575
+ # "When next is used in a loop, any values following the next
576
+ # are ignored"
577
+ #
578
+ # By ignored, it must mean evaluated and the value of the expression
579
+ # is thrown away, because 1.8 evaluates them even though it doesn't
580
+ # use them.
581
+ if @value
582
+ @value.bytecode(g)
583
+ else
584
+ g.push :nil
585
+ end
586
+
587
+ if g.state.loop?
588
+ g.goto g.next
589
+ elsif g.state.block?
590
+ if g.next
591
+ g.goto g.next
592
+ else
593
+ g.ret
594
+ end
595
+ else
596
+ g.pop
597
+
598
+ jump_error g, :next
599
+ end
600
+ end
601
+
602
+ def sexp_name
603
+ :next
604
+ end
605
+ end
606
+
607
+ class Redo < Break
608
+ def initialize(line)
609
+ @line = line
610
+ end
611
+
612
+ def bytecode(g)
613
+ pos(g)
614
+
615
+ if g.redo
616
+ g.check_interrupts
617
+ g.goto g.redo
618
+ else
619
+ jump_error g, :redo
620
+ end
621
+ end
622
+
623
+ def to_sexp
624
+ [:redo]
625
+ end
626
+ end
627
+
628
+ class Retry < Break
629
+ def initialize(line)
630
+ @line = line
631
+ end
632
+
633
+ def bytecode(g)
634
+ pos(g)
635
+
636
+ if g.retry
637
+ g.goto g.retry
638
+ else
639
+ jump_error g, :retry
640
+ end
641
+ end
642
+
643
+ def to_sexp
644
+ [:retry]
645
+ end
646
+ end
647
+
648
+ class Return < Node
649
+ attr_accessor :value
650
+
651
+ def initialize(line, expr)
652
+ @line = line
653
+ @value = expr
654
+ @splat = nil
655
+ end
656
+
657
+ def block=(node)
658
+ @value.block = node if @value
659
+ end
660
+
661
+ def bytecode(g, force=false)
662
+ pos(g)
663
+
664
+ # Literal ArrayList and a splat
665
+ if @splat
666
+ splat_node = @value.body.pop
667
+ @value.bytecode(g)
668
+ splat_node.call_bytecode(g)
669
+ g.send :+, 1
670
+ elsif @value
671
+ @value.bytecode(g)
672
+ else
673
+ g.push :nil
674
+ end
675
+
676
+ if lcl = g.state.rescue?
677
+ g.push_stack_local lcl
678
+ g.restore_exception_state
679
+ end
680
+
681
+ if g.state.block?
682
+ g.raise_return
683
+ elsif !force and g.state.ensure?
684
+ g.ensure_return
685
+ else
686
+ g.ret
687
+ end
688
+ end
689
+
690
+ def to_sexp
691
+ sexp = [:return]
692
+ sexp << @value.to_sexp if @value
693
+ sexp << @splat.to_sexp if @splat
694
+ sexp
695
+ end
696
+ end
697
+ end
698
+ end