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