summaryrefslogtreecommitdiffstats
path: root/unwind.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-04-06 06:31:11 -0700
committerKaz Kylheku <kaz@kylheku.com>2020-04-06 06:31:11 -0700
commit9e4be16274554d469b64e5b240b04fe8549f8a1f (patch)
tree203677f307471db6df8861912b710d74e17771cd /unwind.c
parent49d82c3b34227ec0520eb1cf1bb22083453b49a7 (diff)
downloadtxr-9e4be16274554d469b64e5b240b04fe8549f8a1f.tar.gz
txr-9e4be16274554d469b64e5b240b04fe8549f8a1f.tar.bz2
txr-9e4be16274554d469b64e5b240b04fe8549f8a1f.zip
exceptions: unhandled non-error exceptions now return.
This patch makes a fundamental change in exception behavior. Going forward, if an exception that is not derived from error is not handled (no catch intercepts it, and no handler accepts it) then the throw call simply returns nil to the caller instead of unwinding and terminating the process. For error exceptions, the behavior is the same: the *uhandled-hook* is called, if it exists, and if it doesn't exist or returns, unwinding and termination with diagnostics ensues. The rationale for not treating non-error exceptions fatally is that this simplifies the use of code that throws exceptions for non-error situations like progress updates. The code can be used without the caller having to establish a handler. * txr.1: Documentation updates and comaptibility notes. * unwind.c (uw_rthrow): New returning throw function based on the implementation of uw_throw. (uw_rthrowv, uw_rthrowvf): New functions. (uw_throw): Now a wrapper for uw_rthrow. Because uw_throw still does not return, it calls abort if uw_rthrow returns. uw_throw is used internally only for error exceptions. (uw_throwv, uw_throwfv): Functions removed. (uw_late_init): Register throw and throwf to the new functions uw_rthrowv an uw_rthrowfv. * unwind.h (uw_rthrow, uw_rthrowv, uw_rthrowfv): Declared. (uw_throwv, uw_throwfv): Declarations removed.
Diffstat (limited to 'unwind.c')
-rw-r--r--unwind.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/unwind.c b/unwind.c
index 54847c75..9f0950da 100644
--- a/unwind.c
+++ b/unwind.c
@@ -658,7 +658,7 @@ static void invoke_handler(uw_frame_t *fr, struct args *args)
uw_catch_end;
}
-val uw_throw(val sym, val args)
+val uw_rthrow(val sym, val args)
{
uw_frame_t *ex;
static int reentry_count = 0;
@@ -705,18 +705,28 @@ val uw_throw(val sym, val args)
}
if (ex == 0) {
- if (std_error == 0) {
- fprintf(stderr, "txr: unhandled exception in early initialization\n");
- abort();
- }
-
if (uw_exception_subtype_p(sym, warning_s)) {
--reentry_count;
if (uw_exception_subtype_p(sym, defr_warning_s))
uw_defer_warning(args);
- else
+ else if (std_error != 0)
format(std_error, lit("warning: ~a\n"), car(args), nao);
+ if (!opt_compat || opt_compat >= 234) {
+ uw_rthrow(continue_s, nil);
+ return nil;
+ }
uw_throw(continue_s, nil);
+ }
+
+ if (!opt_compat || opt_compat >= 234) {
+ if (!uw_exception_subtype_p(sym, error_s)) {
+ --reentry_count;
+ return nil;
+ }
+ }
+
+ if (std_error == 0) {
+ fprintf(stderr, "txr: unhandled exception in early initialization\n");
abort();
}
@@ -746,9 +756,23 @@ val uw_throw(val sym, val args)
abort();
}
-val uw_throwv(val sym, struct args *arglist)
+val uw_rthrowv(val sym, struct args *arglist)
{
- uw_throw(sym, args_get_list(arglist));
+ return uw_rthrow(sym, args_get_list(arglist));
+}
+
+val uw_rthrowfv(val sym, val fmt, struct args *args)
+{
+ val stream = make_string_output_stream();
+ (void) formatv(stream, fmt, args);
+ return uw_rthrow(sym, get_string_from_stream(stream));
+ abort();
+}
+
+val uw_throw(val sym, val args)
+{
+ uw_rthrow(sym, args);
+ abort();
}
val uw_throwf(val sym, val fmt, ...)
@@ -764,14 +788,6 @@ val uw_throwf(val sym, val fmt, ...)
abort();
}
-val uw_throwfv(val sym, val fmt, struct args *args)
-{
- val stream = make_string_output_stream();
- (void) formatv(stream, fmt, args);
- uw_throw(sym, get_string_from_stream(stream));
- abort();
-}
-
val uw_errorf(val fmt, ...)
{
va_list vl;
@@ -1280,8 +1296,8 @@ void uw_late_init(void)
reg_mac(intern(lit("defex"), user_package), func_n2(me_defex));
reg_var(unhandled_hook_s = intern(lit("*unhandled-hook*"),
user_package), nil);
- reg_fun(throw_s, func_n1v(uw_throwv));
- reg_fun(intern(lit("throwf"), user_package), func_n2v(uw_throwfv));
+ reg_fun(throw_s, func_n1v(uw_rthrowv));
+ reg_fun(intern(lit("throwf"), user_package), func_n2v(uw_rthrowfv));
reg_fun(error_s, func_n1v(uw_errorfv));
reg_fun(intern(lit("purge-deferred-warning"), user_package),
func_n1(uw_purge_deferred_warning));