summaryrefslogtreecommitdiffstats
path: root/unwind.h
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-07-31 17:33:59 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-07-31 17:40:55 -0700
commit0b38bc996c4c7e2693931bbd5103c7772b56b4bd (patch)
tree8e74fd6b7efc3a0fb87037b2bb58b9d8c6129339 /unwind.h
parent2f5e7a5b96039b7a00543b4056bab7ec85c8db4b (diff)
downloadtxr-0b38bc996c4c7e2693931bbd5103c7772b56b4bd.tar.gz
txr-0b38bc996c4c7e2693931bbd5103c7772b56b4bd.tar.bz2
txr-0b38bc996c4c7e2693931bbd5103c7772b56b4bd.zip
txr-015 2009-10-15txr-015
Diffstat (limited to 'unwind.h')
-rw-r--r--unwind.h92
1 files changed, 90 insertions, 2 deletions
diff --git a/unwind.h b/unwind.h
index 1cd0792a..574794b2 100644
--- a/unwind.h
+++ b/unwind.h
@@ -24,10 +24,16 @@
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifdef __GNUC__
+#define noreturn __attribute__((noreturn))
+#else
+#define noreturn
+#endif
+
typedef union uw_frame uw_frame_t;
typedef enum uw_frtype uw_frtype_t;
-enum uw_frtype { UW_BLOCK, UW_ENV };
+enum uw_frtype { UW_BLOCK, UW_ENV, UW_CATCH };
struct uw_common {
uw_frame_t *up;
@@ -48,20 +54,42 @@ struct uw_dynamic_env {
obj_t *func_bindings;
};
+struct uw_catch {
+ uw_frame_t *up;
+ uw_frtype_t type;
+ obj_t *matches;
+ obj_t *sym;
+ obj_t *exception;
+ uw_frame_t *cont;
+ int visible;
+ jmp_buf jb;
+};
+
union uw_frame {
struct uw_common uw;
struct uw_block bl;
struct uw_dynamic_env ev;
+ struct uw_catch ca;
};
-void uw_init(void);
void uw_push_block(uw_frame_t *, obj_t *tag);
void uw_push_env(uw_frame_t *);
obj_t *uw_get_func(obj_t *sym);
obj_t *uw_set_func(obj_t *sym, obj_t *value);
obj_t *uw_block_return(obj_t *tag, obj_t *result);
+void uw_push_catch(uw_frame_t *, obj_t *matches);
+noreturn obj_t *uw_throw(obj_t *sym, obj_t *exception);
+noreturn obj_t *uw_throwf(obj_t *sym, const char *fmt, ...);
+noreturn obj_t *uw_errorf(const char *fmt, ...);
+noreturn obj_t *uw_throwcf(obj_t *sym, const char *fmt, ...);
+noreturn obj_t *uw_errorcf(const char *fmt, ...);
+void uw_register_subtype(obj_t *sub, obj_t *super);
+obj_t *uw_exception_subtype_p(obj_t *sub, obj_t *sup);
+void uw_continue(uw_frame_t *curr, uw_frame_t *target);
void uw_pop_frame(uw_frame_t *);
+void uw_init(void);
+noreturn obj_t *type_mismatch(const char *, ...);
#define uw_block_begin(TAG, RESULTVAR) \
obj_t *RESULTVAR = nil; \
@@ -85,3 +113,63 @@ void uw_pop_frame(uw_frame_t *);
#define uw_env_end \
uw_pop_frame(&uw_env); \
}
+
+#define uw_catch_begin(MATCHES, SYMVAR, \
+ EXCVAR) \
+ obj_t *SYMVAR = nil; \
+ obj_t *EXCVAR = nil; \
+ { \
+ uw_frame_t uw_catch; \
+ uw_push_catch(&uw_catch, MATCHES); \
+ switch (setjmp(uw_catch.ca.jb)) { \
+ case 0:
+
+#define uw_do_unwind \
+ goto uw_unwind_label
+
+#define uw_catch(SYMVAR, EXCVAR) \
+ break; \
+ case 2: \
+ EXCVAR = uw_catch.ca.exception; \
+ SYMVAR = uw_catch.ca.sym; \
+
+#define uw_unwind \
+ break; \
+ uw_unwind_label: \
+ case 1:
+
+#define uw_catch_end \
+ default: \
+ break; \
+ } \
+ if (uw_catch.ca.cont) \
+ uw_continue(&uw_catch, \
+ uw_catch.ca.cont); \
+ uw_pop_frame(&uw_catch); \
+ }
+
+#define internal_error(STR) \
+ uw_throwcf(internal_err, \
+ "%s:%d %s", __FILE__, \
+ __LINE__, STR)
+
+#define type_assert(EXPR, ARGS) \
+ if (!(EXPR)) type_mismatch ARGS
+
+#define bug_unless(EXPR) \
+ if (!(EXPR)) \
+ internal_error("assertion " \
+ #EXPR \
+ " failed")
+
+#define numeric_assert(EXPR) \
+ if (!(EXPR)) \
+ uw_throwcf(numeric_err, "%s", \
+ "assertion " #EXPR \
+ " failed")
+
+#define range_bug_unless(EXPR) \
+ if (!(EXPR)) \
+ uw_throwcf(range_err, "%s", \
+ "assertion" #EXPR \
+ " failed")