diff options
author | Andy Wingo <wingo@pobox.com> | 2010-01-31 12:35:19 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2010-02-26 11:56:02 +0100 |
commit | e10cf6b9c7e54c79db4de74584f1b0b65847d4fc (patch) | |
tree | 3df9ed5f6b52af3b0ffd5605e2f8834705bb589c | |
parent | d296431516dbf14535fc6eaba551fede19c09772 (diff) |
deprecate lazy-catch
* libguile/deprecated.h:
* libguile/deprecated.c (scm_internal_lazy_catch, scm_lazy_catch):
Deprecate, and print out a nasty warning that people should change to
with-throw-handler.
* libguile/throw.h:
* libguile/throw.c (scm_c_with_throw_handler): Deprecate the use of the
lazy_catch_p argument, printing out a nasty warning if someone
actually passes 1 as that argument. The combination of the pre-unwind
and post-unwind handlers should be sufficient.
* test-suite/tests/exceptions.test: Remove lazy-catch tests, as they are
deprecated. Two of them fail:
* throw/catch: effect of lazy-catch unwinding on throw to another key
* throw/catch: repeat of previous test but with lazy-catch
Hopefully people are not depending on this behavior, and the warning is
sufficiently nasty for people to switch. We will see.
* test-suite/tests/eval.test ("promises"): Use with-throw-handler
instead of lazy-catch.
* doc/ref/api-debug.texi:
* doc/ref/api-control.texi: Update to remove references to lazy-catch,
folding in the useful bits to with-throw-handler.
-rw-r--r-- | doc/ref/api-control.texi | 198 | ||||
-rw-r--r-- | doc/ref/api-debug.texi | 15 | ||||
-rw-r--r-- | libguile/deprecated.c | 50 | ||||
-rw-r--r-- | libguile/deprecated.h | 10 | ||||
-rw-r--r-- | libguile/throw.c | 83 | ||||
-rw-r--r-- | libguile/throw.h | 7 | ||||
-rw-r--r-- | test-suite/tests/eval.test | 30 | ||||
-rw-r--r-- | test-suite/tests/exceptions.test | 153 |
8 files changed, 169 insertions, 377 deletions
diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi index c76bdfe0c..0e84d8948 100644 --- a/doc/ref/api-control.texi +++ b/doc/ref/api-control.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009 +@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 2010 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @@ -606,8 +606,7 @@ more conveniently. @menu * Exception Terminology:: Different ways to say the same thing. * Catch:: Setting up to catch exceptions. -* Throw Handlers:: Adding extra handling to a throw. -* Lazy Catch:: Catch without unwinding the stack. +* Throw Handlers:: Handling exceptions before unwinding the stack. * Throw:: Throwing an exception. * Exception Implementation:: How Guile implements exceptions. @end menu @@ -800,17 +799,53 @@ Operations}). @subsubsection Throw Handlers It's sometimes useful to be able to intercept an exception that is being -thrown, but without changing where in the dynamic context that exception -will eventually be caught. This could be to clean up some related state -or to pass information about the exception to a debugger, for example. -The @code{with-throw-handler} procedure provides a way to do this. +thrown before the stack is unwound. This could be to clean up some +related state, to print a backtrace, or to pass information about the +exception to a debugger, for example. The @code{with-throw-handler} +procedure provides a way to do this. @deffn {Scheme Procedure} with-throw-handler key thunk handler @deffnx {C Function} scm_with_throw_handler (key, thunk, handler) Add @var{handler} to the dynamic context as a throw handler for key @var{key}, then invoke @var{thunk}. + +This behaves exactly like @code{catch}, except that it does not unwind +the stack before invoking @var{handler}. If the @var{handler} procedure +returns normally, Guile rethrows the same exception again to the next +innermost catch or throw handler. @var{handler} may exit nonlocally, of +course, via an explicit throw or via invoking a continuation. @end deffn +Typically @var{handler} is used to display a backtrace of the stack at +the point where the corresponding @code{throw} occurred, or to save off +this information for possible display later. + +Not unwinding the stack means that throwing an exception that is handled +via a throw handler is equivalent to calling the throw handler handler +inline instead of each @code{throw}, and then omitting the surrounding +@code{with-throw-handler}. In other words, + +@lisp +(with-throw-handler 'key + (lambda () @dots{} (throw 'key args @dots{}) @dots{}) + handler) +@end lisp + +@noindent +is mostly equivalent to + +@lisp +((lambda () @dots{} (handler 'key args @dots{}) @dots{})) +@end lisp + +In particular, the dynamic context when @var{handler} is invoked is that +of the site where @code{throw} is called. The examples are not quite +equivalent, because the body of a @code{with-throw-handler} is not in +tail position with respect to the @code{with-throw-handler}, and if +@var{handler} exits normally, Guile arranges to rethrow the error, but +hopefully the intention is clear. (For an introduction to what is meant +by dynamic context, @xref{Dynamic Wind}.) + @deftypefn {C Function} SCM scm_c_with_throw_handler (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data, int lazy_catch_p) The above @code{scm_with_throw_handler} takes Scheme procedures as body (thunk) and handler arguments. @code{scm_c_with_throw_handler} is an @@ -838,141 +873,13 @@ everything that a @code{catch} would do until the point where then it rethrows to the next innermost @code{catch} or throw handler instead. +Note also that since the dynamic context is not unwound, if a +@code{with-throw-handler} handler throws to a key that does not match +the @code{with-throw-handler} expression's @var{key}, the new throw may +be handled by a @code{catch} or throw handler that is @emph{closer} to +the throw than the first @code{with-throw-handler}. -@node Lazy Catch -@subsubsection Catch Without Unwinding - -Before version 1.8, Guile's closest equivalent to -@code{with-throw-handler} was @code{lazy-catch}. From version 1.8 -onwards we recommend using @code{with-throw-handler} because its -behaviour is more useful than that of @code{lazy-catch}, but -@code{lazy-catch} is still supported as well. - -A @dfn{lazy catch} is used in the same way as a normal @code{catch}, -with @var{key}, @var{thunk} and @var{handler} arguments specifying the -exception type, normal case code and handler procedure, but differs in -one important respect: the handler procedure is executed without -unwinding the call stack from the context of the @code{throw} expression -that caused the handler to be invoked. - -@deffn {Scheme Procedure} lazy-catch key thunk handler -@deffnx {C Function} scm_lazy_catch (key, thunk, handler) -This behaves exactly like @code{catch}, except that it does -not unwind the stack before invoking @var{handler}. -If the @var{handler} procedure returns normally, Guile -rethrows the same exception again to the next innermost catch, -lazy-catch or throw handler. If the @var{handler} exits -non-locally, that exit determines the continuation. -@end deffn - -@deftypefn {C Function} SCM scm_internal_lazy_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data) -The above @code{scm_lazy_catch} takes Scheme procedures as body and -handler arguments. @code{scm_internal_lazy_catch} is an equivalent -taking C functions. See @code{scm_internal_catch} (@pxref{Catch}) for -a description of the parameters, the behaviour however of course -follows @code{lazy-catch}. -@end deftypefn - -Typically @var{handler} is used to display a backtrace of the stack at -the point where the corresponding @code{throw} occurred, or to save off -this information for possible display later. - -Not unwinding the stack means that throwing an exception that is caught -by a @code{lazy-catch} is @emph{almost} equivalent to calling the -@code{lazy-catch}'s handler inline instead of each @code{throw}, and -then omitting the surrounding @code{lazy-catch}. In other words, - -@lisp -(lazy-catch 'key - (lambda () @dots{} (throw 'key args @dots{}) @dots{}) - handler) -@end lisp - -@noindent -is @emph{almost} equivalent to - -@lisp -((lambda () @dots{} (handler 'key args @dots{}) @dots{})) -@end lisp - -@noindent -But why only @emph{almost}? The difference is that with -@code{lazy-catch} (as with normal @code{catch}), the dynamic context is -unwound back to just outside the @code{lazy-catch} expression before -invoking the handler. (For an introduction to what is meant by dynamic -context, @xref{Dynamic Wind}.) - -Then, when the handler @emph{itself} throws an exception, that exception -must be caught by some kind of @code{catch} (including perhaps another -@code{lazy-catch}) higher up the call stack. - -The dynamic context also includes @code{with-fluids} blocks -(@pxref{Fluids and Dynamic States}), -so the effect of unwinding the dynamic context can also be seen in fluid -variable values. This is illustrated by the following code, in which -the normal case thunk uses @code{with-fluids} to temporarily change the -value of a fluid: - -@lisp -(define f (make-fluid)) -(fluid-set! f "top level value") - -(define (handler . args) - (cons (fluid-ref f) args)) - -(lazy-catch 'foo - (lambda () - (with-fluids ((f "local value")) - (throw 'foo))) - handler) -@result{} -("top level value" foo) - -((lambda () - (with-fluids ((f "local value")) - (handler 'foo)))) -@result{} -("local value" foo) -@end lisp - -@noindent -In the @code{lazy-catch} version, the unwinding of dynamic context -restores @code{f} to its value outside the @code{with-fluids} block -before the handler is invoked, so the handler's @code{(fluid-ref f)} -returns the external value. - -@code{lazy-catch} is useful because it permits the implementation of -debuggers and other reflective programming tools that need to access the -state of the call stack at the exact point where an exception or an -error is thrown. For an example of this, see REFFIXME:stack-catch. - -It should be obvious from the above that @code{lazy-catch} is very -similar to @code{with-throw-handler}. In fact Guile implements -@code{lazy-catch} in exactly the same way as @code{with-throw-handler}, -except with a flag set to say ``where there are slight differences -between what @code{with-throw-handler} and @code{lazy-catch} would do, -do what @code{lazy-catch} has always done''. There are two such -differences: - -@enumerate -@item -@code{with-throw-handler} handlers execute in the full dynamic context -of the originating @code{throw} call. @code{lazy-catch} handlers -execute in the dynamic context of the @code{lazy-catch} expression, -excepting only that the stack has not yet been unwound from the point of -the @code{throw} call. - -@item -If a @code{with-throw-handler} handler throws to a key that does not -match the @code{with-throw-handler} expression's @var{key}, the new -throw may be handled by a @code{catch} or throw handler that is _closer_ -to the throw than the first @code{with-throw-handler}. If a -@code{lazy-catch} handler throws, it will always be handled by a -@code{catch} or throw handler that is higher up the dynamic context than -the first @code{lazy-catch}. -@end enumerate - -Here is an example to illustrate the second difference: +Here is an example to illustrate this behavior: @lisp (catch 'a @@ -990,14 +897,7 @@ Here is an example to illustrate the second difference: @noindent This code will call @code{inner-handler} and then continue with the -continuation of the inner @code{catch}. If the -@code{with-throw-handler} was changed to @code{lazy-catch}, however, the -code would call @code{outer-handler} and then continue with the -continuation of the outer @code{catch}. - -Modulo these two differences, any statements in the previous and -following subsections about throw handlers apply to lazy catches as -well. +continuation of the inner @code{catch}. @node Throw diff --git a/doc/ref/api-debug.texi b/doc/ref/api-debug.texi index c29bfdf12..3c9ec1137 100644 --- a/doc/ref/api-debug.texi +++ b/doc/ref/api-debug.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2007 +@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2007, 2010 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @@ -400,13 +400,12 @@ equivalent in C. In Scheme, this means you need something like this: @end lisp @noindent -The @code{catch} here can also be @code{lazy-catch} or -@code{with-throw-handler}; see @ref{Throw Handlers} and @ref{Lazy Catch} -for the details of how these differ from @code{catch}. The @code{#t} -means that the catch is applicable to all kinds of error; if you want to -restrict your catch to just one kind of error, you can put the symbol -for that kind of error instead of @code{#t}. The equivalent to this in -C would be something like this: +The @code{catch} here can also be @code{with-throw-handler}; see @ref{Throw +Handlers} for information on the when you might want to use +@code{with-throw-handler} instead of @code{catch}. The @code{#t} means that the +catch is applicable to all kinds of error; if you want to restrict your catch to +just one kind of error, you can put the symbol for that kind of error instead of +@code{#t}. The equivalent to this in C would be something like this: @lisp SCM my_body_proc (void *body_data) diff --git a/libguile/deprecated.c b/libguile/deprecated.c index 54f0055b3..95f6f4662 100644 --- a/libguile/deprecated.c +++ b/libguile/deprecated.c @@ -1816,6 +1816,56 @@ scm_i_subr_p (SCM x) } + +SCM +scm_internal_lazy_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data) +{ + scm_c_issue_deprecation_warning + ("`scm_internal_lazy_catch' is no longer supported. Instead this call will\n" + "dispatch to `scm_c_with_throw_handler'. Your handler will be invoked from\n" + "within the dynamic context of the corresponding `throw'.\n" + "\nTHIS COULD CHANGE YOUR PROGRAM'S BEHAVIOR.\n\n" + "Please modify your program to use `scm_c_with_throw_handler' directly,\n" + "and adapt it (if necessary) to expect to be within the dynamic context\n" + "of the throw."); + return scm_c_with_throw_handler (tag, body, body_data, handler, handler_data, 0); +} + +SCM_DEFINE (scm_lazy_catch, "lazy-catch", 3, 0, 0, + (SCM key, SCM thunk, SCM handler), + "This behaves exactly like @code{catch}, except that it does\n" + "not unwind the stack before invoking @var{handler}.\n" + "If the @var{handler} procedure returns normally, Guile\n" + "rethrows the same exception again to the next innermost catch,\n" + "lazy-catch or throw handler. If the @var{handler} exits\n" + "non-locally, that exit determines the continuation.") +#define FUNC_NAME s_scm_lazy_catch +{ + struct scm_body_thunk_data c; + + SCM_ASSERT (scm_is_symbol (key) || scm_is_eq (key, SCM_BOOL_T), + key, SCM_ARG1, FUNC_NAME); + + c.tag = key; + c.body_proc = thunk; + + scm_c_issue_deprecation_warning + ("`lazy-catch' is no longer supported. Instead this call will dispatch\n" + "to `with-throw-handler'. Your handler will be invoked from within the\n" + "dynamic context of the corresponding `throw'.\n" + "\nTHIS COULD CHANGE YOUR PROGRAM'S BEHAVIOR.\n\n" + "Please modify your program to use `with-throw-handler' directly, and\n" + "adapt it (if necessary) to expect to be within the dynamic context of\n" + "the throw."); + + return scm_c_with_throw_handler (key, + scm_body_thunk, &c, + scm_handle_by_proc, &handler, 0); +} +#undef FUNC_NAME + + + void scm_i_init_deprecated () { diff --git a/libguile/deprecated.h b/libguile/deprecated.h index 9832cfbb0..7f26f3fa0 100644 --- a/libguile/deprecated.h +++ b/libguile/deprecated.h @@ -611,6 +611,16 @@ SCM_DEPRECATED int scm_i_subr_p (SCM x); +/* Deprecated 2010-01-31, use with-throw-handler instead */ +SCM_DEPRECATED SCM scm_lazy_catch (SCM tag, SCM thunk, SCM handler); +SCM_DEPRECATED SCM scm_internal_lazy_catch (SCM tag, + scm_t_catch_body body, + void *body_data, + scm_t_catch_handler handler, + void *handler_data); + + + void scm_i_init_deprecated (void); #endif diff --git a/libguile/throw.c b/libguile/throw.c index fd08e6e70..22d1c4f13 100644 --- a/libguile/throw.c +++ b/libguile/throw.c @@ -30,6 +30,7 @@ #include "libguile/alist.h" #include "libguile/eval.h" #include "libguile/eq.h" +#include "libguile/deprecation.h" #include "libguile/dynwind.h" #include "libguile/backtrace.h" #include "libguile/debug.h" @@ -93,12 +94,11 @@ struct jmp_buf_and_retval /* use only on the stack, in scm_catch */ SCM retval; }; -/* These are the structures we use to store pre-unwind handling (aka - "lazy") information for a regular catch, and put on the wind list - for a "lazy" catch. They store the pre-unwind handler function to - call, and the data pointer to pass through to it. It's not a - Scheme closure, but it is a function with data, so the term - "closure" is appropriate in its broader sense. +/* These are the structures we use to store pre-unwind handling information for + a regular catch, and put on the wind list for a with-throw-handler. They + store the pre-unwind handler function to call, and the data pointer to pass + through to it. It's not a Scheme closure, but it is a function with data, so + the term "closure" is appropriate in its broader sense. (We don't need anything like this to run the normal (post-unwind) catch handler, because the same C frame runs both the body and the @@ -108,7 +108,6 @@ struct pre_unwind_data { scm_t_catch_handler handler; void *handler_data; int running; - int lazy_catch_p; }; @@ -187,7 +186,6 @@ scm_c_catch (SCM tag, pre_unwind.handler = pre_unwind_handler; pre_unwind.handler_data = pre_unwind_handler_data; pre_unwind.running = 0; - pre_unwind.lazy_catch_p = 0; SCM_SETJBPREUNWIND(jmpbuf, &pre_unwind); if (SCM_I_SETJMP (jbr.buf)) @@ -303,9 +301,18 @@ scm_c_with_throw_handler (SCM tag, c.handler = handler; c.handler_data = handler_data; c.running = 0; - c.lazy_catch_p = lazy_catch_p; pre_unwind = make_pre_unwind_data (&c); + if (lazy_catch_p) + scm_c_issue_deprecation_warning + ("The LAZY_CATCH_P argument to `scm_c_with_throw_handler' is no longer.\n" + "supported. Instead the handler will be invoked from within the dynamic\n" + "context of the corresponding `throw'.\n" + "\nTHIS COULD CHANGE YOUR PROGRAM'S BEHAVIOR.\n\n" + "Please modify your program to pass 0 as the LAZY_CATCH_P argument,\n" + "and adapt it (if necessary) to expect to be within the dynamic context\n" + "of the throw."); + SCM_CRITICAL_SECTION_START; scm_i_set_dynwinds (scm_acons (tag, pre_unwind, scm_i_dynwinds ())); SCM_CRITICAL_SECTION_END; @@ -319,15 +326,6 @@ scm_c_with_throw_handler (SCM tag, return answer; } -/* Exactly like scm_internal_catch, except: - - It does not unwind the stack (this is the major difference). - - The handler is not allowed to return. */ -SCM -scm_internal_lazy_catch (SCM tag, scm_t_catch_body body, void *body_data, scm_t_catch_handler handler, void *handler_data) -{ - return scm_c_with_throw_handler (tag, body, body_data, handler, handler_data, 1); -} - /* scm_internal_stack_catch Use this one if you want debugging information to be stored in @@ -354,7 +352,7 @@ static SCM cwss_body (void *data) { struct cwss_data *d = data; - return scm_internal_lazy_catch (d->tag, d->body, d->data, ss_handler, NULL); + return scm_c_with_throw_handler (d->tag, d->body, d->data, ss_handler, NULL, 0); } SCM @@ -566,7 +564,7 @@ scm_handle_by_throw (void *handler_data SCM_UNUSED, SCM tag, SCM args) -/* the Scheme-visible CATCH, WITH-THROW-HANDLER and LAZY-CATCH functions */ +/* the Scheme-visible CATCH and WITH-THROW-HANDLER functions */ SCM_DEFINE (scm_catch_with_pre_unwind_handler, "catch", 3, 1, 0, (SCM key, SCM thunk, SCM handler, SCM pre_unwind_handler), @@ -664,37 +662,6 @@ SCM_DEFINE (scm_with_throw_handler, "with-throw-handler", 3, 0, 0, } #undef FUNC_NAME -SCM_DEFINE (scm_lazy_catch, "lazy-catch", 3, 0, 0, - (SCM key, SCM thunk, SCM handler), - "This behaves exactly like @code{catch}, except that it does\n" - "not unwind the stack before invoking @var{handler}.\n" - "If the @var{handler} procedure returns normally, Guile\n" - "rethrows the same exception again to the next innermost catch,\n" - "lazy-catch or throw handler. If the @var{handler} exits\n" - "non-locally, that exit determines the continuation.") -#define FUNC_NAME s_scm_lazy_catch -{ - struct scm_body_thunk_data c; - - SCM_ASSERT (scm_is_symbol (key) || scm_is_eq (key, SCM_BOOL_T), - key, SCM_ARG1, FUNC_NAME); - - c.tag = key; - c.body_proc = thunk; - - /* scm_internal_lazy_catch takes care of all the mechanics of - setting up a lazy catch key; we tell it to call scm_body_thunk to - run the body, and scm_handle_by_proc to deal with any throws to - this catch. The former receives a pointer to c, telling it how - to behave. The latter receives a pointer to HANDLER, so it knows - who to call. */ - return scm_internal_lazy_catch (key, - scm_body_thunk, &c, - scm_handle_by_proc, &handler); -} -#undef FUNC_NAME - - /* throwing */ @@ -815,19 +782,7 @@ scm_ithrow (SCM key, SCM args, int noreturn SCM_UNUSED) { struct pre_unwind_data *c = (struct pre_unwind_data *) SCM_SMOB_DATA_1 (jmpbuf); - SCM handle, answer; - - /* For old-style lazy-catch behaviour, we unwind the dynamic - context before invoking the handler. */ - if (c->lazy_catch_p) - { - scm_dowinds (wind_goal, (scm_ilength (scm_i_dynwinds ()) - - scm_ilength (wind_goal))); - SCM_CRITICAL_SECTION_START; - handle = scm_i_dynwinds (); - scm_i_set_dynwinds (SCM_CDR (handle)); - SCM_CRITICAL_SECTION_END; - } + SCM answer; /* Call the handler, with framing to set the pre-unwind structure's running field while the handler is running, so we diff --git a/libguile/throw.h b/libguile/throw.h index 1ed6ba6b1..d14cbf839 100644 --- a/libguile/throw.h +++ b/libguile/throw.h @@ -52,12 +52,6 @@ SCM_API SCM scm_internal_catch (SCM tag, scm_t_catch_handler handler, void *handler_data); -SCM_API SCM scm_internal_lazy_catch (SCM tag, - scm_t_catch_body body, - void *body_data, - scm_t_catch_handler handler, - void *handler_data); - SCM_API SCM scm_internal_stack_catch (SCM tag, scm_t_catch_body body, void *body_data, @@ -91,7 +85,6 @@ SCM_API int scm_exit_status (SCM args); SCM_API SCM scm_catch_with_pre_unwind_handler (SCM tag, SCM thunk, SCM handler, SCM lazy_handler); SCM_API SCM scm_catch (SCM tag, SCM thunk, SCM handler); SCM_API SCM scm_with_throw_handler (SCM tag, SCM thunk, SCM handler); -SCM_API SCM scm_lazy_catch (SCM tag, SCM thunk, SCM handler); SCM_API SCM scm_ithrow (SCM key, SCM args, int noreturn); SCM_API SCM scm_throw (SCM key, SCM args); diff --git a/test-suite/tests/eval.test b/test-suite/tests/eval.test index c253b2d09..fd5d75087 100644 --- a/test-suite/tests/eval.test +++ b/test-suite/tests/eval.test @@ -1,5 +1,5 @@ ;;;; eval.test --- tests guile's evaluator -*- scheme -*- -;;;; Copyright (C) 2000, 2001, 2006, 2007, 2009 Free Software Foundation, Inc. +;;;; Copyright (C) 2000, 2001, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public @@ -306,21 +306,19 @@ exception:wrong-type-arg (+ (delay (* 3 7)) 13)) - ;; Tests that require the debugging evaluator... - (with-debugging-evaluator - - (pass-if "unmemoizing a promise" - (display-backtrace - (let ((stack #f)) - (false-if-exception (lazy-catch #t - (lambda () - (let ((f (lambda (g) (delay (g))))) - (force (f error)))) - (lambda _ - (set! stack (make-stack #t))))) - stack) - (%make-void-port "w")) - #t)))) + (pass-if "unmemoizing a promise" + (display-backtrace + (let ((stack #f)) + (false-if-exception + (with-throw-handler #t + (lambda () + (let ((f (lambda (g) (delay (g))))) + (force (f error)))) + (lambda _ + (set! stack (make-stack #t))))) + stack) + (%make-void-port "w")) + #t))) ;;; diff --git a/test-suite/tests/exceptions.test b/test-suite/tests/exceptions.test index c2ec5f48d..bcaa282e5 100644 --- a/test-suite/tests/exceptions.test +++ b/test-suite/tests/exceptions.test @@ -1,5 +1,5 @@ ;;;; exceptions.test --- tests for Guile's exception handling -*- scheme -*- -;;;; Copyright (C) 2001, 2003, 2004, 2006 Free Software Foundation, Inc. +;;;; Copyright (C) 2001, 2003, 2004, 2006, 2010 Free Software Foundation, Inc. ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public @@ -75,9 +75,9 @@ (lambda () (throw 'a)) (lambda (x y . rest) #f)))) - (with-test-prefix "with lazy handler" + (with-test-prefix "with pre-unwind handler" - (pass-if "lazy fluid state" + (pass-if "pre-unwind fluid state" (equal? '(inner outer arg) (let ((fluid-parm (make-fluid)) (inner-val #f)) @@ -102,32 +102,34 @@ (lambda (key . args) (push 2)))) - (throw-test "catch and lazy catch" + (throw-test "catch and with-throw-handler" '(1 2 3 4) (catch 'a (lambda () (push 1) - (lazy-catch 'a - (lambda () - (push 2) - (throw 'a)) - (lambda (key . args) - (push 3)))) + (with-throw-handler + 'a + (lambda () + (push 2) + (throw 'a)) + (lambda (key . args) + (push 3)))) (lambda (key . args) (push 4)))) - (throw-test "catch with rethrowing lazy catch handler" + (throw-test "catch with rethrowing throw-handler" '(1 2 3 4) (catch 'a (lambda () (push 1) - (lazy-catch 'a - (lambda () - (push 2) - (throw 'a)) - (lambda (key . args) - (push 3) - (apply throw key args)))) + (with-throw-handler + 'a + (lambda () + (push 2) + (throw 'a)) + (lambda (key . args) + (push 3) + (apply throw key args)))) (lambda (key . args) (push 4)))) @@ -183,27 +185,6 @@ (lambda (key . args) (push 4)))) - (throw-test "effect of lazy-catch unwinding on throw to another key" - '(1 2 3 5 7) - (catch 'a - (lambda () - (push 1) - (lazy-catch 'b - (lambda () - (push 2) - (catch 'a - (lambda () - (push 3) - (throw 'b)) - (lambda (key . args) - (push 4)))) - (lambda (key . args) - (push 5) - (throw 'a))) - (push 6)) - (lambda (key . args) - (push 7)))) - (throw-test "effect of with-throw-handler not-unwinding on throw to another key" '(1 2 3 5 4 6) (catch 'a @@ -225,27 +206,6 @@ (lambda (key . args) (push 7)))) - (throw-test "lazy-catch chaining" - '(1 2 3 4 6 8) - (catch 'a - (lambda () - (push 1) - (lazy-catch 'a - (lambda () - (push 2) - (lazy-catch 'a - (lambda () - (push 3) - (throw 'a)) - (lambda (key . args) - (push 4))) - (push 5)) - (lambda (key . args) - (push 6))) - (push 7)) - (lambda (key . args) - (push 8)))) - (throw-test "with-throw-handler chaining" '(1 2 3 4 6 8) (catch 'a @@ -267,48 +227,6 @@ (lambda (key . args) (push 8)))) - (throw-test "with-throw-handler inside lazy-catch" - '(1 2 3 4 6 8) - (catch 'a - (lambda () - (push 1) - (lazy-catch 'a - (lambda () - (push 2) - (with-throw-handler 'a - (lambda () - (push 3) - (throw 'a)) - (lambda (key . args) - (push 4))) - (push 5)) - (lambda (key . args) - (push 6))) - (push 7)) - (lambda (key . args) - (push 8)))) - - (throw-test "lazy-catch inside with-throw-handler" - '(1 2 3 4 6 8) - (catch 'a - (lambda () - (push 1) - (with-throw-handler 'a - (lambda () - (push 2) - (lazy-catch 'a - (lambda () - (push 3) - (throw 'a)) - (lambda (key . args) - (push 4))) - (push 5)) - (lambda (key . args) - (push 6))) - (push 7)) - (lambda (key . args) - (push 8)))) - (throw-test "throw handlers throwing to each other recursively" '(1 2 3 4 8 6 10 12) (catch #t @@ -340,37 +258,6 @@ (lambda (key . args) (push 12)))) - (throw-test "repeat of previous test but with lazy-catch" - '(1 2 3 4 8 12) - (catch #t - (lambda () - (push 1) - (lazy-catch 'a - (lambda () - (push 2) - (lazy-catch 'b - (lambda () - (push 3) - (lazy-catch 'c - (lambda () - (push 4) - (throw 'b) - (push 5)) - (lambda (key . args) - (push 6) - (throw 'a))) - (push 7)) - (lambda (key . args) - (push 8) - (throw 'c))) - (push 9)) - (lambda (key . args) - (push 10) - (throw 'b))) - (push 11)) - (lambda (key . args) - (push 12)))) - (throw-test "throw handler throwing to lexically inside catch" '(1 2 7 5 4 6 9) (with-throw-handler 'a |