// Macros to try and make declaring and using exceptions easier // No, these are not part of the language, they replace the virtual system. // Internal use: #define GLUE2(left, right) left##right #define GLUE3(left, middle, right) left##middle##right // The fully (perhaps overly) qualified name of the base exception type: #define BASE_EXCEPT __cfaabi_ehm__base_exception_t // Get the name of the vtable type and vtable instance for an exception type: #define TABLE(name) GLUE2(name,_vtable) #define INSTANCE(name) GLUE3(_,name,_vtable_instance) // Throws and the bit of overhead: #define THROW(expr) throw ((BASE_EXCEPT *)(expr)) #define THROW_RESUME(expr) throwResume ((BASE_EXCEPT *)(expr)) // The following macros are for defining your own new exception types. // Declare vtable and forward declare the exception type and vtable instance. // This should start a new exception declaration. // ... argument is the additional vtable fields. #define DECLARE_EXCEPT(except_name,parent_name,...) \ struct except_name; \ struct TABLE(except_name) { \ struct TABLE(parent_name) const * parent; \ size_t size; \ void (*copy)(except_name *this, except_name * other); \ void (*free)(except_name &this); \ const char * (*msg)(except_name *this); \ __VA_ARGS__ \ }; \ extern TABLE(except_name) INSTANCE(except_name); // The first field of the exception structure should be created with this. #define VTABLE_FIELD(except_name) \ struct TABLE(except_name) const * virtual_table // In each constructor the vtable must be initialized. #define VTABLE_INIT(this_name,except_name) \ this_name.virtual_table = &INSTANCE(except_name) // Declare the vtable instance. This should end an exception declaration. // ... argument is the remaining vtable field values. #define VTABLE_INSTANCE(except_name,parent_name,copy,free,msg,...) \ TABLE(except_name) INSTANCE(except_name) @= { \ &INSTANCE(parent_name), sizeof(except_name), \ copy, free, msg, ## __VA_ARGS__ \ }; // Same, but used declarators for arguments. #define VTABLE_INSTANCE_KEY(except_name,parent_name,copy,free,msg,...) \ TABLE(except_name) INSTANCE(except_name) @= { \ .parent : &INSTANCE(parent_name), .size : sizeof(except_name), \ .copy : copy, .free : free, .msg : msg, ## __VA_ARGS__ \ }; // Declare a trivial exception, one that adds no features: #define TRIVIAL_EXCEPTION(name) \ DECLARE_EXCEPT(name,BASE_EXCEPT,) \ struct name { \ VTABLE_FIELD(name); \ }; \ const char * GLUE2(name,_msg)(name * this) { \ return #name; \ } \ void GLUE2(name,_copy)(name * this, name * other) { \ this->virtual_table = other->virtual_table; \ } \ void ?{}(name & this) { \ VTABLE_INIT(this,name); \ } \ VTABLE_INSTANCE(name,BASE_EXCEPT,GLUE2(name,_copy),^?{},GLUE2(name,_msg),)