2 # Copyright (C) 2001-2007, The Perl Foundation.
7 use lib qw( . lib ../lib ../../lib );
9 use Parrot::Test tests => 33;
13 t/pmc/exception.t - Exception Handling
17 % prove t/pmc/exception.t
21 Tests C<Exception> and C<Exception_Handler> PMCs.
25 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh label - pop_eh" );
38 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh eh - pop_eh" );
39 new P29, 'Exception_Handler'
50 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh - throw" );
65 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh eh - throw" );
67 new P29, 'Exception_Handler'
68 set_addr P29, _handler
82 pasm_output_is( <<'CODE', <<'OUTPUT', "get_results" );
86 set P1[0], "just pining"
91 get_results "0,0", P0, S0
108 pasm_output_is( <<'CODE', <<'OUTPUT', "get_results - be sure registers are ok" );
114 set P1[0], "just pining"
116 print "not reached\n"
119 get_results "0,0", P1, S0
129 pir_output_is( <<'CODE', <<'OUTPUT', ".get_results() - PIR" );
134 set P1[0], "just pining"
136 print "not reached\n"
157 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh - throw - message" );
162 set P30["_message"], "something happend"
164 print "not reached\n"
167 get_results "0,0", P5, S0
178 pasm_error_output_like( <<'CODE', <<'OUTPUT', "throw - no handler" );
180 set P0["_message"], "something happend"
182 print "not reached\n"
188 pasm_error_output_like( <<'CODE', <<'OUTPUT', "throw - no handler, no message" );
193 print "not reached\n"
198 /No exception handler and no message/
201 pasm_error_output_like( <<'CODE', <<'OUTPUT', "throw - no handler, no message" );
204 print "not reached\n"
207 /No exception handler and no message/
210 pasm_output_is( <<'CODE', <<'OUTPUT', "2 exception handlers" );
216 set P30["_message"], "something happend"
218 print "not reached\n"
221 get_results "0,0", P5, S0
222 print "caught it in 1\n"
227 get_results "0,0", P0, S0
228 print "caught it in 2\n"
238 pasm_output_is( <<'CODE', <<'OUTPUT', "2 exception handlers, throw next" );
244 set P30["_message"], "something happend"
246 print "not reached\n"
249 get_results "0,0", P5, S0
250 print "caught it in 1\n"
255 get_results "0,0", P5, S0
256 print "caught it in 2\n"
259 throw P5 # XXX rethrow?
269 pasm_output_is( <<'CODE', <<OUT, "die" );
272 print "not reached\n"
281 pasm_output_is( <<'CODE', <<OUT, "die, error, severity" );
284 print "not reached\n"
287 get_results "0,0", P5, S0
293 set I0, P5["_severity"]
304 pasm_error_output_like( <<'CODE', <<OUT, "die - no handler" );
306 print "not reached\n"
312 /No exception handler and no message/
315 pasm_output_is( <<'CODE', '', "exit exception" );
318 print "not reached\n"
322 pasm_output_is( <<'CODE', <<'OUTPUT', "push_eh - throw" );
328 print "not reached\n"
340 pasm_output_is( <<'CODE', <<'OUTPUT', "pushmark" );
351 pasm_output_is( <<'CODE', <<'OUTPUT', "pushmark nested" );
364 pasm_error_output_like( <<'CODE', <<'OUTPUT', "pushmark - pop wrong one" );
374 pasm_output_is( <<'CODE', <<'OUTPUT', "pushaction, throw" );
377 .const .Sub P10 = "action"
388 print "in action I5 = "
399 pir_output_is( <<'CODE', <<'OUTPUT', 'cleanup global: continuation' );
401 .local pmc outer, cont
403 outer = "Outer value\n"
404 set_global ['Foo'; 'Bar'], "test", outer
405 new cont, 'Continuation'
406 set_addr cont, endcont
407 set_global ['Foo'; 'Bar'], "exit", cont
415 .local pmc test1_binding, old_value, cleanup
416 .lex "old_value", old_value
417 test1_binding = new 'String'
418 test1_binding = "Inner value\n"
419 old_value = get_global ['Foo'; 'Bar'], "test"
420 .const .Sub test1_cleanup_sub = "test1_cleanup"
421 cleanup = newclosure test1_cleanup_sub
423 set_global ['Foo'; 'Bar'], "test", test1_binding
428 .sub test1_cleanup :outer(test1)
430 print "[in test1_cleanup]\n"
431 find_lex old_value, "old_value"
432 set_global ['Foo'; 'Bar'], "test", old_value
435 .local pmc test2_binding, exit
436 test2_binding = new 'String'
437 test2_binding = "Innerer value\n"
438 set_global ['Foo'; 'Bar'], "test", test2_binding
440 exit = get_global ['Foo'; 'Bar'], "exit"
445 value = get_global ['Foo'; 'Bar'], "test"
456 pir_output_is( <<'CODE', <<'OUTPUT', 'cleanup global: throw' );
460 outer = "Outer value\n"
461 set_global ['Foo'; 'Bar'], "test", outer
468 .get_results (exception, $S0)
476 .local pmc test1_binding, old_value, cleanup
477 .lex "old_value", old_value
478 test1_binding = new 'String'
479 test1_binding = "Inner value\n"
480 old_value = get_global ['Foo'; 'Bar'], "test"
481 .const .Sub test1_cleanup_sub = "test1_cleanup"
482 cleanup = newclosure test1_cleanup_sub
484 set_global ['Foo'; 'Bar'], "test", test1_binding
489 .sub test1_cleanup :outer(test1)
491 print "[in test1_cleanup]\n"
492 find_lex old_value, "old_value"
493 set_global ['Foo'; 'Bar'], "test", old_value
496 .local pmc test2_binding, exit
497 test2_binding = new 'String'
498 test2_binding = "Innerer value\n"
499 set_global ['Foo'; 'Bar'], "test", test2_binding
501 exit = new 'Exception'
502 exit["_message"] = "something happened"
507 value = get_global ['Foo'; 'Bar'], "test"
515 Error: something happened
519 pir_error_output_like( <<'CODE', <<'OUTPUT', 'pop_eh out of context (1)' );
523 print "no exceptions.\n"
526 /No exception to pop./
529 pir_output_is( <<'CODE', <<'OUTPUT', 'pop_eh out of context (2)' );
531 .local pmc outer, cont
538 .get_results (exception, $S0)
548 ## pop_eh is illegal here, and signals an exception.
554 Error: No exception to pop.
558 # stringification is handled by a vtable method, which runs in a second
559 # runloop. when an error in the method tries to go to a Error_Handler defined
560 # outside it, it winds up going to the inner runloop, giving strange results.
561 pir_output_is( <<'CODE', <<'OUTPUT', 'pop_eh out of context (2)', todo => 'runloop shenanigans' );
563 $P0 = get_hll_global ['Foo'], 'load'
583 .sub get_string :vtable :method
584 $P0 = new 'Exception'
591 pir_error_output_like( <<'CODE', <<'OUTPUT', "pushaction - throw in main" );
594 .const .Sub at_exit = "exit_handler"
596 $P0 = new 'Exception'
603 print "at_exit, flag = "
608 No exception handler/
611 # exception handlers are still run in an inferior runloop, which messes up
612 # nonlocal exit from within handlers.
614 <<'CODE', <<'OUTPUT', "pushaction: error while handling error", todo => 'runloop shenanigans' );
618 .const .Sub at_exit = "exit_handler"
620 $P1 = new 'Exception'
624 ## this is never actually reached, because exit_handler throws an unhandled
625 ## exception before the handler is entered.
626 print "in outer handler\n"
629 .sub exit_handler :outer(main)
631 print "at_exit, flag = "
633 $P2 = new 'Exception'
640 No exception handler/
643 pir_output_is( <<'CODE', <<'OUTPUT', "exit_handler via exit exception" );
652 .return exit_handler()
655 .sub exit_handler :outer(main)
667 ## Regression test for r14697. This probably won't be needed when PDD23 is
668 ## fully implemented.
669 pir_error_output_like( <<'CODE', <<'OUTPUT', "invoke handler in calling sub" );
670 ## This tests that error handlers are out of scope when invoked (necessary for
671 ## rethrow) when the error is signalled in another sub.
675 print "not reached.\n"
678 .get_results (exception, $S0)
679 print "in handler.\n"
686 $P0 = new 'Exception'
687 $P0["_message"] = "something broke"
697 pir_error_output_like( <<'CODE', <<'OUTPUT', 'die_s' );
699 die 'We are dying str!'
704 pir_error_output_like( <<'CODE', <<'OUTPUT', 'die_p' );
708 msg = 'We are dying pmc!'
717 # cperl-indent-level: 4
720 # vim: expandtab shiftwidth=4: