#include "exception.h" // Use: gcc -fexceptions -Wall -Werror -g exception.c test-main.c #include #include // Helps with manual translation. It may or may not get folded into the // header, that depends on how it interacts with concurancy. void __try_resume_node_new(struct __try_resume_node * node, _Bool (*handler)(exception except)) { node->next = shared_stack.top_resume; shared_stack.top_resume = node; node->try_to_handle = handler; } // Local Print On Exit: struct raii_base_type { const char * area; }; void raii_dtor(struct raii_base_type * this) { printf("Exiting: %s\n", this->area); } #define raii_t __attribute__((cleanup(raii_dtor))) struct raii_base_type // =========================================================================== // Runtime code (post-translation). void terminate(int except_value) { raii_t a = {"terminate function"}; __throw_terminate(except_value); printf("terminate returned\n"); } void resume(int except_value) { raii_t a = {"resume function"}; __throw_resume(except_value); printf("resume returned\n"); } // Termination Test: Two handlers: no catch, catch void bar() { raii_t a = {"bar function"}; { void bar_try1() { terminate(4); } void bar_catch1(int index, exception except) { switch(except) { case 1: printf("bar caught exception 3.\n"); break; default: printf("INVALID INDEX in bar: %d (%d)\n", index, except); } } int bar_match1(exception except) { if (3 == except) { return 1; } else { return 0; } } __try_terminate(bar_try1, bar_catch1, bar_match1); } } void foo() { raii_t a = {"foo function"}; { void foo_try1() { bar(); } void foo_catch1(int index, exception except) { switch(index) { case 1: printf("foo caught exception 4.\n"); break; case 2: printf("foo caught exception 2.\n"); break; default: printf("INVALID INDEX in foo: %d (%d)\n", index, except); } } int foo_match1(exception except) { if (4 == except) { return 1; } else if (2 == except) { return 2; } else { return 0; } } __try_terminate(foo_try1, foo_catch1, foo_match1); } } // Resumption Two Handler Test: no catch, catch. void beta() { raii_t a = {"beta function"}; { bool beta_handle1(exception except) { if (3 == except) { printf("beta caught exception 3\n"); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, beta_handle1); { resume(4); } } } void alpha() { raii_t a = {"alpha function"}; { bool alpha_handle1(exception except) { if (2 == except) { printf("alpha caught exception 2\n"); return true; } else if (4 == except) { printf("alpha caught exception 4\n"); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, alpha_handle1); { beta(); } } } // Finally Test: void farewell(bool jump) { { void farewell_finally1() { printf("See you next time\n"); } struct __cleanup_hook __hidden_hook __attribute__((cleanup(farewell_finally1))); { if (jump) { printf("jump out of farewell\n"); goto endoffunction; } else { printf("walk out of farewell\n"); } } } endoffunction: printf("leaving farewell\n"); } // Resume-to-Terminate Test: void fallback() { { void fallback_try1() { resume(1); } void fallback_catch1(int index, exception except) { switch (index) { case 1: printf("fallback caught termination 1\n"); break; default: printf("INVALID INDEX in fallback: %d (%d)\n", index, except); } } int fallback_match1(exception except) { if (1 == except) { return 1; } else { return 0; } } __try_terminate(fallback_try1, fallback_catch1, fallback_match1); } } // Terminate Throw New Exception: void terminate_swap() { raii_t a = {"terminate_swap"}; { void fn_try1() { terminate(2); } void fn_catch1(int index, exception except) { switch (index) { case 1: terminate(1); break; default: printf("INVALID INDEX in terminate_swap: %d (%d)\n", index, except); } } int fn_match1(exception except) { if (2 == except) { return 1; } else { return 0; } } __try_terminate(fn_try1, fn_catch1, fn_match1); } } void terminate_swapped() { raii_t a = {"terminate_swapped"}; { void fn_try1() { terminate_swap(); } void fn_catch1(int index, exception except) { switch (index) { case 1: printf("terminate_swapped caught exception 1\n"); break; default: printf("INVALID INDEX in terminate_swapped: %d (%d)\n", index, except); } } int fn_match1(exception except) { if (1 == except) { return 1; } else { return 0; } } __try_terminate(fn_try1, fn_catch1, fn_match1); } } // Resume Throw New Exception: void resume_swap() { raii_t a = {"terminate_swap"}; { bool fn_handle1(exception except) { if (2 == except) { resume(1); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, fn_handle1); { resume(2); } } } void resume_swapped() { { bool fn_handle1(exception except) { if (1 == except) { printf("resume_swapped caught exception 1\n"); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, fn_handle1); { resume_swap(); } } } // Terminate Rethrow: // I don't have an implementation for this. void reterminate() { { void fn_try1() { void fn_try2() { terminate(1); } void fn_catch2(int index, exception except) { switch (index) { case 1: printf("reterminate 2 caught and " "will rethrow exception 1\n"); __rethrow_terminate(); break; default: printf("INVALID INDEX in reterminate 2: %d (%d)\n", index, except); } } int fn_match2(exception except) { if (1 == except) { return 1; } else { return 0; } } __try_terminate(fn_try2, fn_catch2, fn_match2); } void fn_catch1(int index, exception except) { switch (index) { case 1: printf("reterminate 1 caught exception 1\n"); break; default: printf("INVALID INDEX in reterminate 1: %d (%d)\n", index, except); } } int fn_match1(exception except) { if (1 == except) { return 1; } else { return 0; } } __try_terminate(fn_try1, fn_catch1, fn_match1); } } // Resume Rethrow: void reresume() { { bool reresume_handle1(exception except) { if (1 == except) { printf("reresume 1 caught exception 1\n"); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, reresume_handle1); { bool reresume_handle2(exception except) { if (1 == except) { printf("reresume 2 caught and rethrows exception 1\n"); return false; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, reresume_handle2); { resume(1); } } } } // Terminate-Resume interaction: void fum() { // terminate block, call resume { void fum_try1() { resume(3); } void fum_catch1(int index, exception except) { switch (index) { case 1: printf("fum caught exception 3\n"); break; default: printf("INVALID INDEX in fum: %d (%d)\n", index, except); } } int fum_match1(exception except) { if (3 == except) { return 1; } else { return 0; } } __try_terminate(fum_try1, fum_catch1, fum_match1); } } void foe() { // resume block, call terminate { bool foe_handle1(exception except) { if (3 == except) { printf("foe caught exception 3\n"); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, foe_handle1); { terminate(3); } } } void fy() { // terminate block calls fum, call foe { void fy_try1() { foe(); } void fy_catch1(int index, exception except) { switch (index) { case 1: printf("fy caught exception 3\n"); fum(); break; default: printf("INVALID INDEX in fy: %d (%d)\n", index, except); } } int fy_match1(exception except) { if (3 == except) { return 1; } else { return 0; } } __try_terminate(fy_try1, fy_catch1, fy_match1); } } void fee() { // resume block, call fy { bool fee_handle1(exception except) { if (3 == except) { printf("fee caught exception 3\n"); return true; } else { return false; } } struct __try_resume_node node __attribute__((cleanup(__try_resume_cleanup))); __try_resume_node_new(&node, fee_handle1); { fy(); } } } // main: choose which tests to run int main(int argc, char * argv[]) { raii_t a = {"main function"}; foo(); printf("\n"); alpha(); printf("\n"); farewell(false); printf("\n"); farewell(true); printf("\n"); fallback(); printf("\n"); terminate_swapped(); printf("\n"); resume_swapped(); printf("\n"); reterminate(); printf("\n"); reresume(); printf("\n"); fee(); printf("\n"); // Uncaught termination test. terminate(7); }