97 lines
2.8 KiB
C
97 lines
2.8 KiB
C
#ifndef EXCEPT_INCLUDED
|
|
#define EXCEPT_INCLUDED
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
#include <setjmp.h>
|
|
#include <errno.h>
|
|
|
|
struct Exception {
|
|
const char *reason;
|
|
};
|
|
typedef struct Exception Exception;
|
|
|
|
struct ExceptFrame {
|
|
struct ExceptFrame *prev; // Exception Stack
|
|
jmp_buf env; // Enviroment Buffer
|
|
const char *file; // Exception File
|
|
int line; // Exception Line
|
|
const Exception *exception; // Exception Reason
|
|
};
|
|
typedef struct ExceptFrame ExceptFrame;
|
|
|
|
// Exception States
|
|
enum { EXCEPT_ENTERED=0, EXCEPT_RAISED, EXCEPT_HANDLED, EXCEPT_FINALIZED};
|
|
|
|
void except_raise(const Exception *e, const char *file,int line); // Raise exceptions
|
|
void hard_fail(const char* fmt, ...); // Errno and exit
|
|
|
|
// External declarations
|
|
extern ExceptFrame *except_stack; // Global exception stack
|
|
extern const Exception assert_failed; // Forward declaration for assert.
|
|
|
|
#undef ASSERT
|
|
#ifdef NDEBUG
|
|
#define ASSERT(e) ((void)0)
|
|
#define TEST(expr)
|
|
#else
|
|
extern void assert(int e);
|
|
#define ASSERT(e) ((void)((e)||(RAISE(assert_failed),0)))
|
|
#define TEST(expr) \
|
|
do { \
|
|
if (expr) { \
|
|
printf(__DATE__" " __TIME__ " [%s@%d] " "\x1b[32m" "| PASSED | " "(%s)" "\x1b[0m \n", __FILE__, __LINE__, #expr); \
|
|
} else { \
|
|
printf(__DATE__" " __TIME__ " [%s@%d] " "\x1b[31m" "| FAILED | " "(%s)" "\x1b[0m \n", __FILE__, __LINE__, #expr); \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
|
|
// Raise an Exception.
|
|
#define RAISE(e) except_raise(&(e), __FILE__, __LINE__)
|
|
|
|
// Reraise the currect exception.
|
|
#define RERAISE except_raise(except_frame.exception, \
|
|
except_frame.file, except_frame.line)
|
|
|
|
// Switch to the previous exception frame and return.
|
|
#define RETURN switch (except_stack = except_stack->prev,0) default: return
|
|
|
|
// Start a try block.
|
|
#define TRY do { \
|
|
volatile int except_flag; \
|
|
ExceptFrame except_frame; \
|
|
except_frame.prev = except_stack; \
|
|
except_stack = &except_frame; \
|
|
except_flag = setjmp(except_frame.env); \
|
|
if (except_flag == EXCEPT_ENTERED) {
|
|
|
|
// Handle specific example.
|
|
#define EXCEPT(e) \
|
|
if (except_flag == EXCEPT_ENTERED) except_stack = except_stack->prev; \
|
|
} else if (except_frame.exception == &(e)) { \
|
|
except_flag = EXCEPT_HANDLED;
|
|
|
|
// Catch all other exceptions.
|
|
#define ELSE \
|
|
if (except_flag == EXCEPT_ENTERED) except_stack = except_stack->prev; \
|
|
} else { \
|
|
except_flag = EXCEPT_HANDLED;
|
|
|
|
// Execute finalization code.
|
|
#define FINALLY \
|
|
if (except_flag == EXCEPT_ENTERED) except_stack = except_stack->prev; \
|
|
} { \
|
|
if (except_flag == EXCEPT_ENTERED) \
|
|
except_flag = EXCEPT_FINALIZED;
|
|
|
|
// End Try block.
|
|
#define END_TRY \
|
|
if (except_flag == EXCEPT_ENTERED) except_stack = except_stack->prev; \
|
|
} if (except_flag == EXCEPT_RAISED) RERAISE; \
|
|
} while (0)
|
|
|
|
#endif
|