rubinius-ast 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class Encoding < Node
6
+ attr_accessor :name
7
+
8
+ def initialize(line, name)
9
+ @line = line
10
+ @name = name
11
+ end
12
+
13
+ def bytecode(g)
14
+ pos(g)
15
+
16
+ g.push_literal Compiler::Runtime
17
+ g.push_literal @name
18
+ g.send :get_encoding, 1
19
+ end
20
+
21
+ def to_sexp
22
+ [:encoding, @name]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,545 @@
1
+ # -*- encoding: us-ascii -*-
2
+
3
+ module Rubinius::ToolSet.current::TS
4
+ module AST
5
+ class Begin < Node
6
+ attr_accessor :rescue
7
+
8
+ def initialize(line, body)
9
+ @line = line
10
+ @rescue = body || NilLiteral.new(line)
11
+ end
12
+
13
+ def bytecode(g)
14
+ @rescue.bytecode(g)
15
+ end
16
+
17
+ def to_sexp
18
+ @rescue.to_sexp
19
+ end
20
+ end
21
+
22
+ EnsureType = 1
23
+
24
+ class Ensure < Node
25
+ attr_accessor :body, :ensure
26
+
27
+ def initialize(line, body, ensr)
28
+ @line = line
29
+ @body = body || NilLiteral.new(line)
30
+ @ensure = ensr
31
+ end
32
+
33
+ def bytecode(g)
34
+ pos(g)
35
+
36
+ ok = g.new_label
37
+ ex = g.new_label
38
+ g.setup_unwind ex, EnsureType
39
+
40
+ # TODO: ?
41
+ g.new_label.set!
42
+
43
+ g.push_exception_state
44
+ outer_exc_state = g.new_stack_local
45
+ g.set_stack_local outer_exc_state
46
+ g.pop
47
+
48
+ old_break = g.break
49
+ new_break = g.new_label
50
+ g.break = new_break
51
+
52
+ old_next = g.next
53
+ new_next = g.new_label
54
+ g.next = new_next
55
+
56
+ g.state.push_ensure
57
+ @body.bytecode(g)
58
+ g.state.pop_ensure
59
+
60
+ g.break = old_break
61
+ g.next = old_next
62
+
63
+ g.pop_unwind
64
+ g.goto ok
65
+
66
+ check_break = nil
67
+
68
+ if new_break.used?
69
+ used_break_local = g.new_stack_local
70
+ check_break = g.new_label
71
+
72
+ new_break.set!
73
+ g.pop_unwind
74
+
75
+ g.push :true
76
+ g.set_stack_local used_break_local
77
+ g.pop
78
+
79
+ g.goto check_break
80
+ end
81
+
82
+ check_next = nil
83
+
84
+ if new_next.used?
85
+ used_next_local = g.new_stack_local
86
+ check_next = g.new_label
87
+
88
+ new_next.set!
89
+ g.pop_unwind
90
+
91
+ g.push :true
92
+ g.set_stack_local used_next_local
93
+ g.pop
94
+
95
+ g.goto check_next
96
+ end
97
+
98
+ ex.set!
99
+
100
+ g.push_exception_state
101
+
102
+ g.state.push_rescue(outer_exc_state)
103
+ @ensure.bytecode(g)
104
+ g.state.pop_rescue
105
+ g.pop
106
+
107
+ g.restore_exception_state
108
+
109
+ # Re-raise the exception
110
+ g.reraise
111
+
112
+ # There is no mapping to the original source here, so
113
+ # reflect that in the lines table to try and make it
114
+ # more accurate.
115
+ g.set_line 0
116
+
117
+ ok.set!
118
+
119
+ if check_break
120
+ g.push :false
121
+ g.set_stack_local used_break_local
122
+ g.pop
123
+
124
+ check_break.set!
125
+ end
126
+
127
+ if check_next
128
+ g.push :false
129
+ g.set_stack_local used_next_local
130
+ g.pop
131
+
132
+ check_next.set!
133
+ end
134
+
135
+ # Now, re-emit the code for the ensure which will run if there was no
136
+ # exception generated.
137
+ @ensure.bytecode(g)
138
+ g.pop
139
+
140
+ if check_break
141
+ post = g.new_label
142
+
143
+ g.push_stack_local used_break_local
144
+ g.gif post
145
+
146
+ if g.break
147
+ g.goto g.break
148
+ else
149
+ g.raise_break
150
+ end
151
+ post.set!
152
+ end
153
+
154
+ if check_next
155
+ post = g.new_label
156
+
157
+ g.push_stack_local used_next_local
158
+ g.gif post
159
+
160
+ g.next ? g.goto(g.next) : g.ret
161
+ post.set!
162
+ end
163
+ end
164
+
165
+ def to_sexp
166
+ [:ensure, @body.to_sexp, @ensure.to_sexp]
167
+ end
168
+ end
169
+
170
+ RescueType = 0
171
+
172
+ class Rescue < Node
173
+ attr_accessor :body, :rescue, :else
174
+
175
+ def initialize(line, body, rescue_body, else_body)
176
+ @line = line
177
+ @body = body
178
+ @rescue = rescue_body
179
+ @else = else_body
180
+ end
181
+
182
+ def bytecode(g)
183
+ pos(g)
184
+
185
+ g.push_modifiers
186
+ if @body.nil?
187
+ if @else.nil?
188
+ # Stupid. No body and no else.
189
+ g.push :nil
190
+ else
191
+ # Only an else, run it.
192
+ @else.bytecode(g)
193
+ end
194
+ else
195
+ outer_retry = g.retry
196
+
197
+ this_retry = g.new_label
198
+ reraise = g.new_label
199
+ els = g.new_label
200
+ done = g.new_label
201
+
202
+ # Save the current exception into a stack local
203
+ g.push_exception_state
204
+ outer_exc_state = g.new_stack_local
205
+ g.set_stack_local outer_exc_state
206
+ g.pop
207
+
208
+ this_retry.set!
209
+ ex = g.new_label
210
+ g.setup_unwind ex, RescueType
211
+
212
+ # TODO: ?
213
+ g.new_label.set!
214
+
215
+ if current_break = g.break
216
+ # Make a break available to use, which we'll use to
217
+ # lazily generate a cleanup area
218
+ g.break = g.new_label
219
+ end
220
+
221
+ # Setup a lazy cleanup area for next'ing out of the handler
222
+ current_next = g.next
223
+ g.next = g.new_label
224
+
225
+ # Use a lazy label to patch up prematuraly leaving a begin
226
+ # body via retry.
227
+ if outer_retry
228
+ g.retry = g.new_label
229
+ end
230
+
231
+ # Also handle redo unwinding through the rescue
232
+ if current_redo = g.redo
233
+ g.redo = g.new_label
234
+ end
235
+
236
+ @body.bytecode(g)
237
+ g.pop_unwind
238
+ g.goto els
239
+
240
+ if current_break
241
+ if g.break.used?
242
+ g.break.set!
243
+ g.pop_unwind
244
+
245
+ # Reset the outer exception
246
+ g.push_stack_local outer_exc_state
247
+ g.restore_exception_state
248
+
249
+ g.goto current_break
250
+ end
251
+
252
+ g.break = current_break
253
+ end
254
+
255
+ if g.next.used?
256
+ g.next.set!
257
+ g.pop_unwind
258
+
259
+ # Reset the outer exception
260
+ g.push_stack_local outer_exc_state
261
+ g.restore_exception_state
262
+
263
+ if current_next
264
+ g.goto current_next
265
+ else
266
+ g.ret
267
+ end
268
+ end
269
+
270
+ g.next = current_next
271
+
272
+ if current_redo
273
+ if g.redo.used?
274
+ g.redo.set!
275
+ g.pop_unwind
276
+
277
+ # Reset the outer exception
278
+ g.push_stack_local outer_exc_state
279
+ g.restore_exception_state
280
+
281
+ g.goto current_redo
282
+ end
283
+
284
+ g.redo = current_redo
285
+ end
286
+
287
+ if outer_retry
288
+ if g.retry.used?
289
+ g.retry.set!
290
+ g.pop_unwind
291
+
292
+ # Reset the outer exception
293
+ g.push_stack_local outer_exc_state
294
+ g.restore_exception_state
295
+
296
+ g.goto outer_retry
297
+ end
298
+
299
+ g.retry = outer_retry
300
+ end
301
+
302
+ g.set_line 0
303
+
304
+ # We jump here if an exception has occured in the body
305
+ ex.set!
306
+
307
+ # Expose the retry label here only, not before this.
308
+ g.retry = this_retry
309
+
310
+ # Save exception state to use in reraise
311
+ g.push_exception_state
312
+
313
+ raised_exc_state = g.new_stack_local
314
+ g.set_stack_local raised_exc_state
315
+ g.pop
316
+
317
+ # Save the current exception, so that calling #=== can't trample
318
+ # it.
319
+ g.push_current_exception
320
+
321
+ @rescue.bytecode(g, reraise, done, outer_exc_state)
322
+ reraise.set!
323
+
324
+ # Restore the exception state we saved and the reraise. The act
325
+ # of checking if an exception matches can run any code, which
326
+ # can easily trample on the current exception.
327
+ #
328
+ # Remove the direct exception so we can get to the state
329
+ g.pop
330
+
331
+ # Restore the state and reraise
332
+ g.push_stack_local raised_exc_state
333
+ g.restore_exception_state
334
+ g.reraise
335
+
336
+ els.set!
337
+ if @else
338
+ g.pop
339
+ @else.bytecode(g)
340
+ end
341
+
342
+ g.set_line 0
343
+ done.set!
344
+
345
+ g.push_stack_local outer_exc_state
346
+ g.restore_exception_state
347
+ end
348
+ g.pop_modifiers
349
+ end
350
+
351
+ def to_sexp
352
+ sexp = [:rescue, @body.to_sexp, @rescue.to_sexp]
353
+ sexp << @else.to_sexp if @else
354
+ sexp
355
+ end
356
+ end
357
+
358
+ class RescueCondition < Node
359
+ attr_accessor :conditions, :assignment, :body, :next, :splat
360
+
361
+ def initialize(line, conditions, body, nxt)
362
+ @line = line
363
+ @next = nxt
364
+ @splat = nil
365
+ @assignment = nil
366
+
367
+ case conditions
368
+ when ArrayLiteral
369
+ @conditions = conditions
370
+ when ConcatArgs
371
+ @conditions = conditions.array
372
+ @splat = RescueSplat.new line, conditions.rest
373
+ when SplatValue
374
+ @splat = RescueSplat.new line, conditions.value
375
+ when nil
376
+ condition = ConstantAccess.new line, :StandardError, true
377
+ @conditions = ArrayLiteral.new line, [condition]
378
+ end
379
+
380
+ case body
381
+ when Block
382
+ @assignment = body.array.shift if assignment? body.array.first
383
+ @body = body
384
+ when nil
385
+ @body = NilLiteral.new line
386
+ else
387
+ if assignment? body
388
+ @assignment = body
389
+ @body = NilLiteral.new line
390
+ else
391
+ @body = body
392
+ end
393
+ end
394
+ end
395
+
396
+ def assignment?(node)
397
+ case node
398
+ when VariableAssignment
399
+ value = node.value
400
+ when AttributeAssignment
401
+ value = node.arguments.array.last
402
+ else
403
+ return false
404
+ end
405
+
406
+ return true if value.kind_of? CurrentException
407
+ end
408
+
409
+ def bytecode(g, reraise, done, outer_exc_state)
410
+ pos(g)
411
+ body = g.new_label
412
+
413
+ # Exception has left the current exception on the top
414
+ # of the stack, use it rather than using push_current_exception.
415
+
416
+ if @conditions
417
+ @conditions.body.each do |c|
418
+ g.dup
419
+ c.bytecode(g)
420
+ g.swap
421
+ g.send :===, 1
422
+ g.git body
423
+ end
424
+ end
425
+
426
+ @splat.bytecode(g, body) if @splat
427
+
428
+ if @next
429
+ if_false = g.new_label
430
+ g.goto if_false
431
+ else
432
+ g.goto reraise
433
+ end
434
+
435
+ body.set!
436
+
437
+ # Remove the current exception from the top of the stack now
438
+ # that we've hit a handler
439
+ g.pop
440
+
441
+ if @assignment
442
+ @assignment.bytecode(g)
443
+ g.pop
444
+ end
445
+
446
+ current_break = g.break
447
+ g.break = g.new_label
448
+
449
+ current_next = g.next
450
+ g.next = g.new_label
451
+
452
+ g.state.push_rescue(outer_exc_state)
453
+ @body.bytecode(g)
454
+ g.state.pop_rescue
455
+
456
+ g.clear_exception
457
+ g.goto done
458
+
459
+ if g.break.used?
460
+ g.break.set!
461
+ g.clear_exception
462
+
463
+ # Reset the outer exception
464
+ g.push_stack_local outer_exc_state
465
+ g.restore_exception_state
466
+
467
+ if current_break
468
+ g.goto current_break
469
+ else
470
+ g.raise_break
471
+ end
472
+ end
473
+
474
+ g.break = current_break
475
+
476
+ if g.next.used?
477
+ g.next.set!
478
+
479
+ g.clear_exception
480
+
481
+ # Reset the outer exception
482
+ g.push_stack_local outer_exc_state
483
+ g.restore_exception_state
484
+
485
+ if current_next
486
+ g.goto current_next
487
+ else
488
+ g.ret
489
+ end
490
+ end
491
+
492
+ g.next = current_next
493
+
494
+ if @next
495
+ if_false.set!
496
+ @next.bytecode(g, reraise, done, outer_exc_state)
497
+ end
498
+ end
499
+
500
+ def to_sexp
501
+ array = @conditions.to_sexp
502
+ array << @assignment.to_sexp if @assignment
503
+ array << @splat.to_sexp if @splat
504
+
505
+ sexp = [:resbody, array]
506
+ case @body
507
+ when Block
508
+ sexp << (@body ? @body.array.map { |x| x.to_sexp } : nil)
509
+ when nil
510
+ sexp << nil
511
+ else
512
+ sexp << @body.to_sexp
513
+ end
514
+
515
+ sexp << @next.to_sexp if @next
516
+
517
+ sexp
518
+ end
519
+ end
520
+
521
+ class RescueSplat < Node
522
+ attr_accessor :value
523
+
524
+ def initialize(line, value)
525
+ @line = line
526
+ @value = value
527
+ end
528
+
529
+ def bytecode(g, body)
530
+ pos(g)
531
+
532
+ g.dup
533
+ @value.bytecode(g)
534
+ g.cast_array
535
+ g.swap
536
+ g.send :__rescue_match__, 1
537
+ g.git body
538
+ end
539
+
540
+ def to_sexp
541
+ [:splat, @value.to_sexp]
542
+ end
543
+ end
544
+ end
545
+ end