/* Copyright 2009 * Kaz Kylheku * Vancouver, Canada * All rights reserved. * * BSD License: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * 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, UW_CATCH }; struct uw_common { uw_frame_t *up; uw_frtype_t type; }; struct uw_block { uw_frame_t *up; uw_frtype_t type; obj_t *tag; obj_t *result; jmp_buf jb; }; struct uw_dynamic_env { uw_frame_t *up; uw_frtype_t type; 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_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, ...); obj_t *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; \ { \ uw_frame_t uw_blk; \ uw_push_block(&uw_blk, TAG); \ if (setjmp(uw_blk.bl.jb)) { \ RESULTVAR = uw_blk.bl.result; \ } else { #define uw_block_end \ } \ uw_pop_frame(&uw_blk); \ } #define uw_env_begin \ { \ uw_frame_t uw_env; \ uw_push_env(&uw_env) #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")