diff options
| author | kr.angelov <kr.angelov@gmail.com> | 2012-01-20 13:41:10 +0000 |
|---|---|---|
| committer | kr.angelov <kr.angelov@gmail.com> | 2012-01-20 13:41:10 +0000 |
| commit | 2eee382a62a909d5a3f2f5eda94f30fe68fd5335 (patch) | |
| tree | b0b0d513535895f244214aebf6358e172b8dce6d /src/runtime/c/gu/exn.h | |
| parent | b9728357126f8b9a6311cca17d9f0dcc2a7bfb9b (diff) | |
initial import of the C runtime
Diffstat (limited to 'src/runtime/c/gu/exn.h')
| -rw-r--r-- | src/runtime/c/gu/exn.h | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/runtime/c/gu/exn.h b/src/runtime/c/gu/exn.h new file mode 100644 index 000000000..66ca107e3 --- /dev/null +++ b/src/runtime/c/gu/exn.h @@ -0,0 +1,195 @@ +#ifndef GU_EXN_H_ +#define GU_EXN_H_ + +#include <gu/mem.h> +#include <gu/type.h> + +/** @file + * + * @defgroup GuExn Exceptions + * Defined in <gu/exn.h>. + * @{ + */ + +/// An exception frame. +typedef struct GuExn GuExn; + +/// @private +typedef enum { + GU_EXN_RAISED, + GU_EXN_OK, + GU_EXN_BLOCKED +} GuExnState; + +typedef struct GuExnData GuExnData; + +/// A structure for storing exception values. +struct GuExnData +/** + * When an exception is raised, if there is an associated value, it + * must be allocated from a pool that still exists when control + * returns to the handler of that exception. This structure is used to + * communicate the exception from the raiser to the handler: the + * handler sets #pool when setting up the exception frame, and the + * raiser uses that pool to allocate the value and stores that in + * #data. When control returns to the handler, it reads the value from + * there. + */ +{ + + /// The pool that the exception value should be allocated from. + GuPool* const pool; + + /// The exception value. + const void* data; +}; + +struct GuExn { + /// @privatesection + GuExnState state; + GuExn* parent; + GuKind* catch; + GuType* caught; + GuExnData data; +}; + + +/// @name Creating exception frames +//@{ + + +/// Allocate a new local exception frame. +#define gu_exn(parent_, catch_, pool_) &(GuExn){ \ + .state = GU_EXN_OK, \ + .parent = parent_, \ + .catch = gu_kind(catch_), \ + .caught = NULL, \ + .data.pool = pool_, \ + .data.data = NULL \ +} + + +/// Allocate a new exception frame. +GuExn* +gu_new_exn(GuExn* parent, GuKind* catch_kind, GuPool* pool); + + + +static inline bool +gu_exn_is_raised(GuExn* err) { + return err && (err->state == GU_EXN_RAISED); +} + +static inline void +gu_exn_clear(GuExn* err) { + err->caught = NULL; + err->state = GU_EXN_OK; +} + + + +GuType* +gu_exn_caught(GuExn* err); + +const void* +gu_exn_caught_data(GuExn* err); + +/// Temporarily block a raised exception. +void +gu_exn_block(GuExn* err); + +/// Show again a blocked exception. +void +gu_exn_unblock(GuExn* err); + +//@private +GuExnData* +gu_exn_raise_(GuExn* err, GuType* type); + +//@private +GuExnData* +gu_exn_raise_debug_(GuExn* err, GuType* type, + const char* filename, const char* func, int lineno); + +#ifdef NDEBUG +#define gu_exn_raise(err_, type_) \ + gu_exn_raise_(err_, type_) +#else +#define gu_exn_raise(err_, type_) \ + gu_exn_raise_debug_(err_, type_, \ + __FILE__, __func__, __LINE__) +#endif + +/// Raise an exception. +#define gu_raise(exn, T) \ + gu_exn_raise(exn, gu_type(T)) +/**< + * @param exn The current exception frame. + * + * @param T The C type of the exception to raise. + * + * @return A #GuExnData object that can be used to store the exception value, or + * \c NULL if no value is required. + * + * @note The associated #GuType object for type \p T must be visible. + */ + +#define gu_raise_new(error_, t_, pool_, expr_) \ + GU_BEGIN \ + GuExnData* gu_raise_err_ = gu_raise(error_, t_); \ + if (gu_raise_err_) { \ + GuPool* pool_ = gu_raise_err_->pool; \ + gu_raise_err_->data = expr_; \ + } \ + GU_END + +#define gu_raise_i(error_, t_, ...) \ + gu_raise_new(error_, t_, gu_raise_pool_, gu_new_i(gu_raise_pool_, t_, __VA_ARGS__)) + + +/// Check the status of the current exception frame +static inline bool +gu_ok(GuExn* exn) { + return !GU_UNLIKELY(gu_exn_is_raised(exn)); +} +/**< + * @return \c false if an exception has been raised in the frame \p exn + * and it has not been blocked, \c true otherwise. + */ + + +/// Return from current function if an exception has been raised. +#define gu_return_on_exn(exn_, retval_) \ + GU_BEGIN \ + if (gu_exn_is_raised(exn_)) return retval_; \ + GU_END +/**< + * @showinitializer + */ + + +#include <errno.h> + +typedef int GuErrno; + +extern GU_DECLARE_TYPE(GuErrno, signed); + + + +#define gu_raise_errno(error_) \ + gu_raise_i(error_, GuErrno, errno) + +#if 0 + +typedef void (*GuExnPrintFn)(GuFn* clo, void* err, FILE* out); + +extern GuTypeTable gu_exn_default_printer; + +void +gu_exn_print(GuExn* err, FILE* out, GuTypeMap printer_map); + +#endif + +/** @} */ + +#endif // GU_EXN_H_ |
