tagged release 0.7.1
[parrot.git] / t / op / exceptions.t
blobc5403bc281878e3b8a82d226f74debae2518b7e2
1 #! perl
2 # Copyright (C) 2001-2008, The Perl Foundation.
3 # $Id$
5 use strict;
6 use warnings;
7 use lib qw( . lib ../lib ../../lib );
8 use Test::More;
9 use Parrot::Test tests => 30;
11 =head1 NAME
13 t/op/exceptions.t - Exception Handling
15 =head1 SYNOPSIS
17     % prove t/op/exceptions.t
19 =head1 DESCRIPTION
21 Tests C<Exception> and C<ExceptionHandler> PMCs.
23 =cut
25 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh label - pop_eh" );
26     push_eh _handler
27     print "ok 1\n"
28     pop_eh
29     print "ok 2\n"
30     end
31 _handler:
32     end
33 CODE
34 ok 1
35 ok 2
36 OUTPUT
38 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh eh - pop_eh" );
39     new P29, 'ExceptionHandler'
40     push_eh P29
41     print "ok 1\n"
42     pop_eh
43     print "ok 2\n"
44     end
45 CODE
46 ok 1
47 ok 2
48 OUTPUT
50 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh - throw" );
51     print "main\n"
52     push_eh _handler
53     new P30, 'Exception'
54     throw P30
55     print "not reached\n"
56     end
57 _handler:
58     print "caught it\n"
59     end
60 CODE
61 main
62 caught it
63 OUTPUT
65 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh eh - throw" );
66     print "main\n"
67     new P29, 'ExceptionHandler'
68     set_addr P29, _handler
69     push_eh P29
70     new P30, 'Exception'
71     throw P30
72     print "not reached\n"
73     end
74 _handler:
75     print "caught it\n"
76     end
77 CODE
78 main
79 caught it
80 OUTPUT
82 pasm_output_is( <<'CODE', <<'OUTPUT', "get_results" );
83     print "main\n"
84     push_eh handler
85     new P1, 'Exception'
86     set P1, "just pining"
87     throw P1
88     print "not reached\n"
89     end
90 handler:
91     get_results "0,0", P0, S0
92     print "caught it\n"
93     typeof S1, P0
94     print S1
95     print "\n"
96     print S0
97     print "\n"
98     null P5
99     end
101 CODE
102 main
103 caught it
104 Exception
105 just pining
106 OUTPUT
108 pasm_output_is( <<'CODE', <<'OUTPUT', "get_results - be sure registers are ok" );
109 # see also #38459
110     print "main\n"
111     new P0, 'Integer'
112     push_eh handler
113     new P1, 'Exception'
114     set P1, "just pining"
115     throw P1
116     print "not reached\n"
117     end
118 handler:
119     get_results "0,0", P1, S0
120     inc P0
121     print "ok\n"
122     end
124 CODE
125 main
127 OUTPUT
129 pir_output_is( <<'CODE', <<'OUTPUT', ".get_results() - PIR" );
130 .sub main :main
131     print "main\n"
132     push_eh _handler
133     new P1, 'Exception'
134     set P1, "just pining"
135     throw P1
136     print "not reached\n"
137     end
138 _handler:
139     .local pmc e
140     .local string s
141     .get_results (e, s)
142     print "caught it\n"
143     typeof S1, e
144     print S1
145     print "\n"
146     print s
147     print "\n"
148     null P5
149 .end
150 CODE
151 main
152 caught it
153 Exception
154 just pining
155 OUTPUT
157 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh - throw - message" );
158     print "main\n"
159     push_eh _handler
161     new P30, 'Exception'
162     set P30, "something happend"
163     throw P30
164     print "not reached\n"
165     end
166 _handler:
167     get_results "0,0", P5, S0
168     print "caught it\n"
169     print S0
170     print "\n"
171     end
172 CODE
173 main
174 caught it
175 something happend
176 OUTPUT
178 pasm_error_output_like( <<'CODE', <<'OUTPUT', "throw - no handler" );
179     new P0, 'Exception'
180     set P0, "something happend"
181     throw P0
182     print "not reached\n"
183     end
184 CODE
185 /something happend/
186 OUTPUT
188 pasm_error_output_like( <<'CODE', <<'OUTPUT', "throw - no handler, no message" );
189     push_eh _handler
190     new P0, 'Exception'
191     pop_eh
192     throw P0
193     print "not reached\n"
194     end
195 _handler:
196     end
197 CODE
198 /No exception handler and no message/
199 OUTPUT
201 pasm_error_output_like( <<'CODE', <<'OUTPUT', "throw - no handler, no message" );
202     new P0, 'Exception'
203     throw P0
204     print "not reached\n"
205     end
206 CODE
207 /No exception handler and no message/
208 OUTPUT
210 pasm_output_is( <<'CODE', <<'OUTPUT', "2 exception handlers" );
211     print "main\n"
212     push_eh _handler1
213     push_eh _handler2
215     new P30, 'Exception'
216     set P30, "something happend"
217     throw P30
218     print "not reached\n"
219     end
220 _handler1:
221     get_results "0,0", P5, S0
222     print "caught it in 1\n"
223     print S0
224     print "\n"
225     end
226 _handler2:
227     get_results "0,0", P0, S0
228     print "caught it in 2\n"
229     print S0
230     print "\n"
231     end
232 CODE
233 main
234 caught it in 2
235 something happend
236 OUTPUT
238 pasm_output_is( <<'CODE', <<'OUTPUT', "2 exception handlers, throw next" );
239     print "main\n"
240     push_eh _handler1
241     push_eh _handler2
243     new P30, 'Exception'
244     set P30, "something happend"
245     throw P30
246     print "not reached\n"
247     end
248 _handler1:
249     get_results "0,0", P5, S0
250     print "caught it in 1\n"
251     print S0
252     print "\n"
253     end
254 _handler2:
255     get_results "0,0", P5, S0
256     print "caught it in 2\n"
257     print S0
258     print "\n"
259     rethrow P5
260     end
261 CODE
262 main
263 caught it in 2
264 something happend
265 caught it in 1
266 something happend
267 OUTPUT
269 pasm_output_is( <<'CODE', <<OUT, "die" );
270     push_eh _handler
271     die 3, 100
272     print "not reached\n"
273     end
274 _handler:
275     print "caught it\n"
276     end
277 CODE
278 caught it
281 pasm_output_is( <<'CODE', <<OUT, "die, error, severity" );
282     push_eh _handler
283     die 3, 100
284     print "not reached\n"
285     end
286 _handler:
287     get_results "0,0", P5, S0
288     print "caught it\n"
289     set I0, P5['severity']
290     print "severity "
291     print I0
292     print "\n"
293     end
294 CODE
295 caught it
296 severity 3
299 pasm_error_output_like( <<'CODE', <<OUT, "die - no handler" );
300     die 3, 100
301     print "not reached\n"
302     end
303 _handler:
304     print "caught it\n"
305     end
306 CODE
307 /No exception handler and no message/
310 pasm_output_is( <<'CODE', '', "exit exception" );
311     noop
312     exit 0
313     print "not reached\n"
314     end
315 CODE
317 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh - throw" );
318     print "main\n"
319     push_eh handler
320     print "ok\n"
321     new P30, 'Exception'
322     throw P30
323     print "not reached\n"
324     end
325 handler:
326     print "caught it\n"
327     end
328 CODE
329 main
331 caught it
332 OUTPUT
335 pir_error_output_like( <<'CODE', <<'OUTPUT', 'pop_eh with no handler' );
336 .sub main :main
337     pop_eh
338     print "no exceptions.\n"
339 .end
340 CODE
341 /No handler to delete./
342 OUTPUT
344 pir_output_is( <<'CODE', <<'OUTPUT', 'pop_eh out of context (2)');
345 .sub main :main
346     .local pmc outer, cont
347     push_eh handler
348     test1()
349     print "skipped.\n"
350     goto done
351 handler:
352     .local pmc exception
353     .get_results (exception, $S0)
354     print "Error: "
355     print $S0
356     print "\n"
357 done:
358     print "done.\n"
359 .end
360 .sub test1
361     .local pmc exit
362     print "[in test1]\n"
363     ## pop_eh is illegal here, and signals an exception.
364     pop_eh
365     print "[cleared]\n"
366 .end
367 CODE
368 [in test1]
369 Error: No handler to delete.
370 done.
371 OUTPUT
373 # stringification is handled by a vtable method, which runs in a second
374 # runloop. when an error in the method tries to go to a Error_Handler defined
375 # outside it, it winds up going to the inner runloop, giving strange results.
376 pir_output_is( <<'CODE', <<'OUTPUT', 'pop_eh out of context (2)', todo => 'runloop shenanigans' );
377 .sub main :main
378         $P0 = get_hll_global ['Foo'], 'load'
379         $P0()
380         $P0 = new 'Foo'
381         push_eh catch
382         $S0 = $P0
383         pop_eh
384         say "huh?"
385         .return()
387 catch:
388         say "caught"
389         .return()
390 .end
392 .namespace ['Foo']
394 .sub load
395     $P0 = newclass 'Foo'
396 .end
398 .sub get_string :vtable :method
399     $P0 = new 'Exception'
400     throw $P0
401 .end
402 CODE
403 caught
404 OUTPUT
406 pir_error_output_like( <<'CODE', <<'OUTPUT', "throw in main, no handler" );
407 .sub main :main
408     print "main\n"
409     $P0 = new 'Exception'
410     throw $P0
411     .return()
412 .end
413 CODE
414 /^main
415 No exception handler/
416 OUTPUT
418 pir_output_is( <<'CODE', <<'OUTPUT', "exit_handler via exit exception" );
419 .sub main :main
420     .local pmc a
421     .lex 'a', a
422     a = new 'Integer'
423     a = 42
424     push_eh handler
425     exit 0
426 handler:
427     .return exit_handler()
428 .end
430 .sub exit_handler :outer(main)
431     say "at_exit"
432     .local pmc a
433     a = find_lex 'a'
434     print 'a = '
435     say a
436 .end
437 CODE
438 at_exit
439 a = 42
440 OUTPUT
442 ## Regression test for r14697.  This probably won't be needed when PDD23 is
443 ## fully implemented.
444 pir_error_output_like( <<'CODE', <<'OUTPUT', "invoke handler in calling sub" );
445 ## This tests that error handlers are out of scope when invoked (necessary for
446 ## rethrow) when the error is signalled in another sub.
447 .sub main :main
448     push_eh handler
449     broken()
450     print "not reached.\n"
451 handler:
452     .local pmc exception
453     .get_results (exception, $S0)
454     print "in handler.\n"
455     print $S0
456     print "\n"
457     rethrow exception
458 .end
460 .sub broken
461     $P0 = new 'Exception'
462     $P0 = "something broke"
463     throw $P0
464 .end
465 CODE
466 /\Ain handler.
467 something broke
468 something broke
469 current inst/
470 OUTPUT
472 pir_error_output_like( <<'CODE', <<'OUTPUT', 'die_s' );
473 .sub main :main
474     die 'We are dying str!'
475 .end
476 CODE
477 /We are dying str!/
478 OUTPUT
479 pir_error_output_like( <<'CODE', <<'OUTPUT', 'die_p' );
480 .sub main :main
481     .local pmc msg
482     msg = new 'String'
483     msg = 'We are dying pmc!'
484     die msg
485 .end
486 CODE
487 /We are dying pmc!/
488 OUTPUT
490 pir_output_is( <<'CODE', <<'OUTPUT', "resuming after exception handled - goto label" );
491 .sub main :main
492     print "before calling setup_foo\n"
493     setup_foo()
494     print "after calling setup_foo\n"
495     end
496 .end
498 .sub setup_foo
499     print "in setup_foo\n"
500     newclass $P0, "Foo"
501     push_eh handler
502     newclass $P0, "Foo"
503     pop_eh
504 resume:
505     print "running more code\n"
506     .return()
507 handler:
508     print "in handler\n"
509     goto resume
510 .end
512 CODE
513 before calling setup_foo
514 in setup_foo
515 in handler
516 running more code
517 after calling setup_foo
518 OUTPUT
520 pir_output_is( <<'CODE', <<'OUTPUT', "resuming after exception handled - return from cont" );
521 .sub main :main
522     print "before calling setup_foo\n"
523     setup_foo()
524     print "after calling setup_foo\n"
525     end
526 .end
528 .sub setup_foo
529     print "in setup_foo\n"
530     newclass $P0, "Foo"
531     push_eh handler
532     newclass $P0, "Foo"
533     pop_eh
534 resume:
535     print "never reached\n"
536 handler:
537     print "in handler\n"
538     .return()
539 .end
540 CODE
541 before calling setup_foo
542 in setup_foo
543 in handler
544 after calling setup_foo
545 OUTPUT
548 pir_output_is( <<'CODE', <<'OUTPUT', "resuming after exception handled - return from cont" );
549 # This test is a simplified version of PGE's grammar creation code.
551 .sub main :main
552     $P1 = newclass 'FirstClass'
553     $P1 = newclass 'MakerClass'
555     $P0 = new 'String'
556     $P0 = 'Foo'
557     $P1 = newclass $P0
559     print "before compile\n"
560     compile($P0)
561     print "after compile\n"
562     end
563 .end
565 .sub compile
566     .param string classname
567     print "in compile subroutine\n"
568     $P0 = new 'FirstClass'
569     $P1 = $P0.'compile'(classname)
570     print "returned from handler\nException message: "
571     print $P1
572 .end
574 .namespace [ "FirstClass" ]
575 .sub 'compile' :method
576     .param pmc name
577     print "in compile method\n"
578     $P1 = new 'String'
579     $P1 = "no exception\n"
580   make_grammar:
581     push_eh handler
582     $P0 = new 'MakerClass'
583     $P0.'make'(name)
584     pop_eh
585     .return($P1)
586   handler:
587     get_results "0,0", $P2, $S2
588     print "in handler\n"
589   .return ($P2)
590 .end
592 .namespace [ "MakerClass" ]
593 .sub 'make' :method
594     .param pmc name
595     print "in make method\n"
596     $P0 = newclass name
597     print "after newclass, never reached\n"
598 .end
600 CODE
601 before compile
602 in compile subroutine
603 in compile method
604 in make method
605 in handler
606 returned from handler
607 Exception message: Class Foo already registered!
608 after compile
609 OUTPUT
611 pir_output_is( <<'CODE', <<'OUTPUT', "Resumable exceptions" );
612 .sub main :main
613     push_eh _handler
614     new $P1, 'Exception'
615     say 'Before throwing'
616     throw $P1
617     say 'After throwing'
618     end
619 _handler:
620     .local pmc e
621     .local string s
622     .local pmc c
623     .get_results (e, s)
624     say 'In the exception handler'
625     c = e['resume']
626     c()
627 .end
628 CODE
629 Before throwing
630 In the exception handler
631 After throwing
632 OUTPUT
634 # Local Variables:
635 #   mode: cperl
636 #   cperl-indent-level: 4
637 #   fill-column: 100
638 # End:
639 # vim: expandtab shiftwidth=4: