// New draft of exception tests. #include // Local Exception Types and manual vtable types. #define GLUE2(left, right) left##right #define GLUE3(left, middle, right) left##middle##right #define BASE_EXCEPT __cfaehm__base_exception_t #define TABLE(name) GLUE2(name,_vtable) #define INSTANCE(name) GLUE3(_,name,_vtable_instance) #define TRIVIAL_EXCEPTION(name) \ struct name; \ struct TABLE(name) { \ struct TABLE(BASE_EXCEPT) const * parent; \ size_t size; \ void (*copy)(name *this, name * other); \ void (*free)(name *this); \ const char * (*msg)(name *this); \ }; \ extern TABLE(name) INSTANCE(name); \ struct name { \ struct TABLE(name) const * virtual_table; \ }; \ const char * name##_msg(name * this) { \ return #name; \ } \ void name##_copy(name * this, name * other) { \ this->virtual_table = other->virtual_table; \ } \ TABLE(name) INSTANCE(name) @= { \ .parent : &INSTANCE(BASE_EXCEPT), \ .size : sizeof(name), .copy : name##_copy, \ .free : ^?{}, .msg : name##_msg \ }; \ void ?{}(name * this) { \ this->virtual_table = &INSTANCE(name); \ } TRIVIAL_EXCEPTION(yin) TRIVIAL_EXCEPTION(yang) struct num_error; struct num_error_vtable { struct TABLE(BASE_EXCEPT) const * parent; size_t size; void (*copy)(num_error *this, num_error * other); void (*free)(num_error *this); const char * (*msg)(num_error *this); int (*code)(num_error *this); }; extern num_error_vtable INSTANCE(num_error); struct num_error { struct num_error_vtable const * virtual_table; char * msg; int num; }; void num_error_msg(num_error * this) { if ( ! this->msg ) { const char * base = "Num Error with code: X"; this->msg = strdup( base ); } this->msg[21] = '0' + this->num; return this->msg; } void ?{}(num_error * this, int num) { this->virtual_table = &INSTANCE(num_error); this->msg = 0; this->num = num; } void ?{}(num_error * this, num_error * other) { this->virtual_table = other->virtual_table; this->msg = 0; this->num = other->num; } void ^?{}(num_error * this) { if( this->msg ) free( this->msg ); } int num_error_code( num_error * this ) { return this->num; } num_error_vtable _num_error_vtable_instance @= { &INSTANCE(BASE_EXCEPT), sizeof(num_error), ?{}, ^?{}, num_error_msg, num_error_code }; // Test simple throwing, matching and catching. void throw_catch() { try { yin black; throw (BASE_EXCEPT *)&black; } catch ( yin * error ) { printf("throw yin caught.\n"); } try { yang white; throwResume (BASE_EXCEPT *)&white; printf("> throwResume returned.\n"); } catchResume ( yang * error ) { printf("throwResume yang caught <"); } try { num_error x = { 2 }; throw (BASE_EXCEPT *)&x; } catch (num_error * error ; 3 == error->virtual_table->code( error ) ) { printf("exception at %p\n", error ); printf("Should not be printed.\n"); } catch (num_error * error ; 2 == error->virtual_table->code( error ) ) { printf("Should be printed.\n"); } } int main (int argc, char * argv[]) { throw_catch(); return 0; }