Next: restarts restart-case, Previous: restarts ignore-errors, Up: restarts [Index]
Evaluate body forms in a dynamic environment in which new exception
handlers are installed; it is capable of handling exceptions raised with
raise, raise-continuable and signal. Not quite
like R6RS’s with-exception-handler syntax, but similar.
The arguments ?clause must have the following syntax:
(?typespec ?condition-handler)
Every ?typespec is meant to be a logic predicate with the format:
?typespec = (?tag)
| (and ?inner-pred0 ?inner-pred ...)
| (or ?inner-pred0 ?inner-pred ...)
| (xor ?inner-pred0 ?inner-pred ...)
| (not ?inner-pred)
?inner-pred = ?tag
| (and ?inner-pred0 ?inner-pred ...)
| (or ?inner-pred0 ?inner-pred ...)
| (xor ?inner-pred0 ?inner-pred ...)
| (not ?inner-pred)
where: each ?tag is an identifier usable as second argument to
is-a?; and, or, xor, not
are the identifiers exported by (vicare).
Every ?condition-handler must be an expression evaluating to a procedure accepting a condition object as single argument; the condition object can be simple or compound.
If the body performs a normal return: the values returned by the body
become the values returned by handler-bind.
If an exception is raised (in Common Lisp jargon: a condition is signalled): a condition handler matching the raised object is searched in the sequence of clauses, left–to–right:
raise-continuable.
The handlers are called with a continuation whose dynamic environment is
that of the call to raise, raise-continuable or
signal that raised the exception; except that the current
exception handler is the one that was in place when
handler-bind was evaluated.
When a condition handler is applied to the raised condition object:
raise-continuable.
Usage examples on handling raised conditions:
(import (vicare)
(only (vicare checks)
with-result
add-result))
;;no condition
(with-result
(handler-bind
((&error (lambda (E)
(add-result 'error-handler)
1))
(&warning (lambda (E)
(add-result 'warning-handler)
2)))
(add-result 'body)
1))
⇒ (1 (body))
;;;
;;Escaping from handler, which is the normal way of accepting
;;to handle a condition.
;;
(with-result
(call/cc
(lambda (escape)
(handler-bind
((&error (lambda (E)
(add-result 'error-handler)
(escape 2))))
(add-result 'body-begin)
(signal (make-error))
(add-result 'body-return)
1))))
⇒ (2 (body-begin error-handler))
;;The first handler declines to handle a raised exception,
;;the second one accepts.
;;
(with-result
(call/cc
(lambda (escape)
(handler-bind
((&warning (lambda (E)
;;By returning this handler declines.
(add-result 'warning-handler)))
(&error (lambda (E)
(add-result 'error-handler)
(escape 2))))
(add-result 'body-begin)
(raise (condition (make-error)
(make-warning)))
(add-result 'body-return)
1))))
⇒ (2 (body-begin warning-handler error-handler))
;;Multiple condition identifiers in the same clause.
;;
(with-result
(call/cc
(lambda (escape)
(handler-bind
(((&warning &error) (lambda (E)
(add-result 'handler)
(escape 2))))
(add-result 'body-begin)
(signal (make-error))
(add-result 'body-return)
1))))
⇒ (2 (body-begin handler))
;;Nested HANDLER-BIND uses, returning from handler.
;;
(with-result
(call/cc
(lambda (escape)
(handler-bind
((&error (lambda (E)
(add-result 'outer-error-handler)
(escape 2))))
(handler-bind
((&error (lambda (E)
(add-result 'inner-error-handler))))
(add-result 'body-begin)
(raise (make-error))
(add-result 'body-return)
1)))))
⇒ (2 (body-begin inner-error-handler outer-error-handler))
;;; unwind-protect
(internal-body
(define (doit C)
(with-result
(returnable
(handler-bind
((&error (lambda (E)
(add-result 'error-handler)
(return 1))))
(with-unwind-handler
(lambda (why)
(add-result 'outer-unwind-handler))
(lambda ()
(handler-bind
((&warning (lambda (E)
(add-result 'warning-handler)
(return 2))))
(with-unwind-handler
(lambda (why)
(add-result 'inner-unwind-handler))
(lambda ()
(add-result 'body-begin)
(signal C)
(add-result 'body-normal-return))))))))))
(doit (make-error))
⇒ (1
(body-begin
error-handler
inner-unwind-handler
outer-unwind-handler))
(doit (make-warning))
⇒ (2
(body-begin
warning-handler
inner-unwind-handler
outer-unwind-handler))
#| end of body |# )
Usage examples on invoking restarts:
(import (vicare)
(only (vicare checks)
with-result
add-result))
;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition,
;;call a handler, invoke a restart.
;;
(internal-body
(define (restarts-outside/handlers-inside C)
(with-result
(restart-case
(handler-bind
((&error (lambda (E)
(add-result 'error-handler-begin)
(invoke-restart 'alpha)
(add-result 'error-handler-return)))
(&warning (lambda (E)
(add-result 'warning-handler-begin)
(invoke-restart 'beta)
(add-result 'warning-handler-return))))
(begin
(add-result 'body-begin)
(signal C)
(add-result 'body-return)))
(alpha (lambda ()
(add-result 'restart-alpha)
1))
(beta (lambda ()
(add-result 'restart-beta)
2)))))
(restarts-outside/handlers-inside (make-error))
⇒ (1 (body-begin error-handler-begin restart-alpha))
(restarts-outside/handlers-inside (make-warning))
⇒ (2 (body-begin warning-handler-begin restart-beta))
#| end of body |# )
;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition,
;;call a handler, invoke a restart.
;;
(internal-body
(define (restarts-inside/handlers-outside C)
(with-result
(handler-bind
((&error (lambda (E)
(add-result 'error-handler-begin)
(invoke-restart 'alpha)
(add-result 'error-handler-return)))
(&warning (lambda (E)
(add-result 'warning-handler-begin)
(invoke-restart 'beta)
(add-result 'warning-handler-return))))
(restart-case
(begin
(add-result 'body-begin)
(signal C)
(add-result 'body-return))
(alpha (lambda ()
(add-result 'restart-alpha)
1))
(beta (lambda ()
(add-result 'restart-beta)
2))))))
(restarts-inside/handlers-outside (make-error))
⇒ (1 (body-begin error-handler-begin restart-alpha))
(restarts-inside/handlers-outside (make-warning))
⇒ (2 (body-begin warning-handler-begin restart-beta))
#| end of body |# )
;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition,
;;call a handler, invoke a restart.
;;
(internal-body
(define (restarts-inside/nested-handlers C)
(with-result
(handler-bind
((&error (lambda (E)
(add-result 'error-handler-begin)
(invoke-restart 'alpha)
(add-result 'error-handler-return))))
(handler-bind
((&warning (lambda (E)
(add-result 'warning-handler-begin)
(invoke-restart 'beta)
(add-result 'warning-handler-return))))
(restart-case
(begin
(add-result 'body-begin)
(signal C)
(add-result 'body-return))
(alpha (lambda ()
(add-result 'restart-alpha)
1))
(beta (lambda ()
(add-result 'restart-beta)
2)))))))
(restarts-inside/nested-handlers (make-error))
⇒ (1 (body-begin error-handler-begin restart-alpha))
(restarts-inside/nested-handlers (make-warning))
⇒ (2 (body-begin warning-handler-begin restart-beta))
#| end of LET |# )
;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition,
;;call a handler, invoke a restart.
;;
(internal-body
(define (nested-restarts/handlers-outside C)
(with-result
(handler-bind
((&error (lambda (E)
(add-result 'error-handler)
(invoke-restart 'alpha)))
(&warning (lambda (E)
(add-result 'warning-handler)
(cond ((find-restart 'beta)
=> (lambda (handler)
(invoke-restart handler)))))))
(restart-case
(restart-case
(begin
(add-result 'body-begin)
(signal C)
(add-result 'body-return))
(alpha (lambda ()
(add-result 'restart-alpha)
1)))
(beta (lambda ()
(add-result 'restart-beta)
2))))))
(nested-restarts/handlers-outside (make-error))
⇒ (1 (body-begin error-handler restart-alpha))
(nested-restarts/handlers-outside (make-warning))
⇒ (2 (body-begin warning-handler restart-beta))
#| end of body |# )
;;Nested RESTART-CASE and HANDLER-BIND. Signal a condition,
;;call the first handler, the first handler declines, call
;;the second handler, invoke a restart.
;;
(with-result
(handler-bind
((&message (lambda (E)
(add-result 'outer-message-handler-begin)
(invoke-restart 'alpha E)
(add-result 'outer-message-handler-return))))
(handler-bind
((&message (lambda (E)
(add-result 'inner-message-handler))))
(restart-case
(begin
(add-result 'body-begin)
(signal (make-message-condition "ciao"))
(add-result 'body-return))
(alpha (lambda (E)
(add-result 'alpha-restart)
(condition-message E)))))))
⇒ ("ciao"
(body-begin
inner-message-handler
outer-message-handler-begin
alpha-restart))
Next: restarts restart-case, Previous: restarts ignore-errors, Up: restarts [Index]