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