// Tests for providing new default operations. #include #include DATA_EXCEPTION(log_message)( char * msg; ); void ?{}(log_message & this, char * msg) { VTABLE_INIT(this, log_message); this.msg = msg; } const char * get_log_message(log_message * this) { return this->msg; } VTABLE_INSTANCE(log_message)(get_log_message); // Logging messages don't have to be handled. void defaultResumptionHandler(log_message &) {} // And should never be used to terminate computation. void defaultTerminationHandler(log_message &) = void; void log_test(void) { // We can catch log: try { throwResume (log_message){"Should be printed.\n"}; } catchResume (log_message * this) { printf("%s", this->virtual_table->msg(this)); } // But we don't have to: throwResume (log_message){"Should not be printed.\n"}; } // I don't have a good use case for doing the same with termination. TRIVIAL_EXCEPTION(jump); void defaultTerminationHandler(jump &) { printf("jump default handler.\n"); } void jump_test(void) { try { throw (jump){}; } catch (jump * this) { printf("jump catch handler.\n"); } throw (jump){}; } TRIVIAL_EXCEPTION(first); TRIVIAL_EXCEPTION(unhandled_exception); void unhandled_test(void) { forall(T &, V & | is_exception(T, V)) void defaultTerminationHandler(T &) { throw (unhandled_exception){}; } void defaultTerminationHandler(unhandled_exception &) { abort(); } try { throw (first){}; } catch (unhandled_exception * t) { printf("Catch unhandled_exception.\n"); } } TRIVIAL_EXCEPTION(second); void cross_test(void) { void defaultTerminationHandler(first &) { printf("cross terminate default\n"); throw (second){}; } void defaultResumptionHandler(first &) { printf("cross resume default\n"); throwResume (second){}; } try { printf("cross terminate throw\n"); throw (first){}; } catch (second *) { printf("cross terminate catch\n"); } try { printf("cross resume throw\n"); throwResume (first){}; } catchResume (second *) { printf("cross resume catch\n"); } } int main(int argc, char * argv[]) { log_test(); jump_test(); unhandled_test(); cross_test(); }