diff --git a/cii/CMakeLists.txt b/cii/CMakeLists.txt index 8ad9a63d..e9a3fb4e 100644 --- a/cii/CMakeLists.txt +++ b/cii/CMakeLists.txt @@ -5,10 +5,12 @@ set(CMAKE_C_STANDARD 11) set(SOURCE_FILES src/atom.c + src/except.c src/hash.c ) set(HEADER_FILES include/cii/atom.h + include/cii/except.h include/cii/hash.h ) diff --git a/cii/include/cii/except.h b/cii/include/cii/except.h new file mode 100644 index 00000000..d1893b11 --- /dev/null +++ b/cii/include/cii/except.h @@ -0,0 +1,96 @@ +// Copyright (c) 2023 Xu Shaohua . All rights reserved. +// Use of this source is governed by GNU General Public License +// that can be found in the LICENSE file. + +#ifndef CII_EXCEPT_H_ +#define CII_EXCEPT_H_ + +#include + +struct except_s { + int type; + const char* reason; +}; + +typedef struct except_s except_t; + +struct except_frame_s { + struct except_frame_s* prev; + jmp_buf env; + const char* file; + int line; + const except_t* exception; +}; + +typedef struct except_frame_s except_frame_t; + +// Global exception stack frame. +extern except_frame_t* g_except_stack; + +enum except_state_e { + except_state_entered = 0, + except_state_raised, + except_state_handled, + except_state_finalized, +}; + +/** + * It is a checked runtime error if e is null. + * + * @param e is a pointer to global or static except_t instance. + * @param file source file name where exception occurs. + * @param line line number where exception occurs. + */ +void except_raise(const except_t* e, const char* file, int line); + +#define RAISE(e) except_raise(&(e), __FILE__, __LINE__) + +#define REREAISE \ + except_raise(except_frame.exception, except_frame.file, except_frame.line) + +#define RETURN switch(0) default: return + +#define TRY \ +do { \ + volatile except_state_e except_flag; \ + except_frame_t except_frame; \ + except_frame.prev = g_except_stack; \ + g_except_stack = &except_frame; \ + except_flag = setjmp(except_frame.env); \ + if (except_flag == except_state_entered) { \ + +#define EXCEPT(e) \ + if (except_flag == except_state_entered) { \ + g_except_stack = except_stack->prev; \ + } \ + } else if (except_frame.exception == &(e)) { \ + except_flag = except_state_handled; + +#define ELSE \ + if (except_flag == except_state_entered) { \ + g_except_stack = except_stack->prev; \ + } \ + } else { \ + except_flag = except_state_handled; + +#define FINALLY \ + if (except_flag == except_state_entered) { \ + g_except_stack = except_stack->prev; \ + } \ + } \ + { \ + if (except_flag == except_state_entered) { \ + except_flag = except_state_finalized; \ + } + +#define END_TRY \ + if (except_flag == except_state_entered) { \ + g_except_stack = except_stack->prev; \ + } \ + } \ + if (except_flag == except_raised) { \ + RERAISE; \ + } \ +} while (0) + +#endif // CII_EXCEPT_H_ diff --git a/cii/include/cii/mem.h b/cii/include/cii/mem.h new file mode 100644 index 00000000..16b7f2e1 --- /dev/null +++ b/cii/include/cii/mem.h @@ -0,0 +1,16 @@ +// Copyright (c) 2023 Xu Shaohua . All rights reserved. +// Use of this source is governed by GNU General Public License +// that can be found in the LICENSE file. + +#ifndef CII_MEM_H_ +#define CII_MEM_H_ + +#include + +extern const except_t mem_failed; + +void* mem_alloc(size_t nbytes, const char* file, int line); + +void* mem_calloc(size_t count, size_t nbytes, const char* file, int line); + +#endif // CII_MEM_H_ diff --git a/cii/src/except.c b/cii/src/except.c new file mode 100644 index 00000000..f966555a --- /dev/null +++ b/cii/src/except.c @@ -0,0 +1,42 @@ +// Copyright (c) 2023 Xu Shaohua . All rights reserved. +// Use of this source is governed by GNU General Public License +// that can be found in the LICENSE file. + +#include "cii/except.h" + +#include +#include +#include +#include + +except_frame_t* g_except_stack = NULL; + +void except_raise(const except_t* e, const char* file, int line) { + except_frame_t* frame = g_except_stack; + assert(e != NULL); + + if (frame == NULL) { + // uncaught exception. + fprintf(stderr, "Uncaught exception"); + if (e->reason != NULL) { + fprintf(stderr, " %s", e->reason); + } else { + fprintf(stderr, " at 0x%p", e); + } + if (file != NULL && line > 0) { + fprintf(stderr, " raised at %s:%d\n", file, line); + } else { + fprintf(stderr, "\n"); + } + fprintf(stderr, "aborting...\n"); + fflush(stderr); + abort(); + } + + frame->exception = e; + frame->file = file; + frame->line = line; + // pop except frame. + g_except_stack = frame->prev; + longjmp(frame->env, except_state_raised); +} \ No newline at end of file diff --git a/cii/src/mem.c b/cii/src/mem.c new file mode 100644 index 00000000..ea036944 --- /dev/null +++ b/cii/src/mem.c @@ -0,0 +1,6 @@ +// Copyright (c) 2023 Xu Shaohua . All rights reserved. +// Use of this source is governed by GNU General Public License +// that can be found in the LICENSE file. + +#include "cii/mem.h" +