// // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // exception.hfa -- User facing tools for working with exceptions. // // Author : Andrew Beach // Created On : Thu Apr 7 10:25:00 2020 // Last Modified By : Andrew Beach // Last Modified On : Tue May 19 14:17:00 2020 // Update Count : 2 // // Everything below this line should be considered a patch while the exception // objects themselves are designed and created and should be removed in time. // ----------------------------------------------------------------------------------------------- // All internals helper macros begin with an underscore. #define _CLOSE(...) __VA_ARGS__ } #define _GLUE2(left, right) left##right #define _GLUE3(left, middle, right) left##middle##right #define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,) // FWD_TRIVIAL_EXCEPTION(exception_name); // Declare a trivial exception, one that adds no fields or features. // This will make the exception visible and may go in a .hfa or .cfa file. #define FWD_TRIVIAL_EXCEPTION(...) _EXC_DISPATCH(_FWD_TRIVIAL_EXCEPTION, __VA_ARGS__) // INST_TRIVIAL_EXCEPTION(exception_name); // Create the trival exception. This must be used exactly once and should be used in a .cfa file, // as it creates the unique instance of the virtual table. #define INST_TRIVIAL_EXCEPTION(...) _EXC_DISPATCH(_INST_TRIVIAL_EXCEPTION, __VA_ARGS__) // TRIVIAL_EXCEPTION(exception_name[, parent_name]); // Does both of the above, a short hand if the exception is only used in one .cfa file. // For legacy reasons this is the only one that official supports having a parent other than the // base exception. This feature may be removed or changed. #define TRIVIAL_EXCEPTION(...) \ _EXC_DISPATCH(_FWD_TRIVIAL_EXCEPTION, __VA_ARGS__); \ _EXC_DISPATCH(_INST_TRIVIAL_EXCEPTION, __VA_ARGS__) #define _FWD_TRIVIAL_EXCEPTION(exception_name, parent_name, ...) \ _VTABLE_DECLARATION(exception_name, parent_name)(); \ struct exception_name { \ VTABLE_FIELD(exception_name); \ }; \ void ?{}(exception_name & this); \ const char * _GLUE2(exception_name,_msg)(exception_name * this) #define _INST_TRIVIAL_EXCEPTION(exception_name, parent_name, ...) \ void ?{}(exception_name & this) { \ VTABLE_INIT(this, exception_name); \ } \ const char * _GLUE2(exception_name,_msg)(exception_name * this) { \ return #exception_name; \ } \ _VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg)) // DATA_EXCEPTION(exception_name)(fields...); // Forward declare an exception that adds fields but no features. The added fields go in the // second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE). #define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__) #define _DATA_EXCEPTION(exception_name, parent_name, ...) \ _VTABLE_DECLARATION(exception_name, parent_name)(); \ struct exception_name { VTABLE_FIELD(exception_name); _CLOSE // VTABLE_DECLARATION(exception_name)([new_features...]); // Declare a virtual table type for an exception with exception_name. You may also add features // (fields on the virtual table) by including them in the second list. #define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__) #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ struct exception_name; \ void mark_exception(exception_name *); \ VTABLE_TYPE(exception_name); \ extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ VTABLE_TYPE(exception_name) { \ VTABLE_TYPE(parent_name) const * parent; \ size_t size; \ void (*copy)(exception_name * this, exception_name * other); \ void (*free)(exception_name & this); \ const char * (*msg)(exception_name * this); \ _CLOSE // VTABLE_INSTANCE(exception_name)(msg [, others...]); // Create the instance of the virtual table. There must be exactly one instance of a virtual table // for each exception type. This fills in most of the fields of the virtual table (uses ?=? and // ^?{}) but you must provide the message function and any other fields added in the declaration. #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ void mark_exception(exception_name *) {} \ void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ *this = *other; \ } \ VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \ &VTABLE_NAME(parent_name), sizeof(exception_name), \ _GLUE2(exception_name,_copy), ^?{}, \ _CLOSE // VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name) // Get the name of the vtable type or the name of the vtable instance for an exception type. #define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable) #define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance) // VTABLE_FIELD(exception_name); // The declaration of the virtual table field. Should be the first declaration in a virtual type. #define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table // VTABLE_INIT(object_reference, exception_name); // Sets a virtual table field on an object to the virtual table instance for the type. #define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name)