Next: , Previous: , Up: restarts   [Index]


1.18.2 Catching signalled conditions

Syntax: handler-case (?clause …) ?body0 ?body

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. Basically behave like R6RS’s guard syntax.

The arguments ?clause must have one of the following syntaxes:

(?typespec ?condition-handler)
(:no-error ?no-error-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.

In the no–error clause: :no-error must be the actual symbol; ?no-error-handler must be an expression evaluating to a procedure. The optional :no-error clause can be present only if it is the last one.

If the body performs a normal return:

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:

Usage examples:

(import (vicare)
  (only (vicare checks)
        with-result
        add-result))

;;no condition
(with-result
  (handler-case
      ((&error   (lambda (E)
                   (add-result 'error-handler)
                   1))
       (&warning (lambda (E)
                   (add-result 'warning-handler)
                   2)))
    (add-result 'body)
    1))
⇒ (1 (body))

;;no condition, :no-error clause
(with-result
  (handler-case
      ((&error    (lambda (E)
                    (add-result 'error-handler)
                    1))
       (&warning  (lambda (E)
                    (add-result 'warning-handler)
                    2))
       (:no-error (lambda (X)
                    (add-result 'no-error)
                    (* 10 X))))
    (add-result 'body)
    1))
⇒ (10 (body no-error))

;;;

(internal-body        ;signalled condition

  (define (doit C)
    (with-result
      (handler-case
          ((&error   (lambda (E)
                       (add-result 'error-handler)
                       1))
           (&warning (lambda (E)
                       (add-result 'warning-handler)
                       2)))
        (add-result 'body-begin)
        (signal C)
        (add-result 'body-normal-return))))

  (doit (make-error))
  ⇒ (1 (body-begin error-handler))

  (doit (make-warning))
  ⇒ (2 (body-begin warning-handler))

  #| end of body |# )

;;Signalled condition, multiple types in single clause.
;;
(internal-body

  (define (doit C)
    (with-result
      (handler-case
          (((&error &warning) (lambda (E)
                                (add-result 'handler)
                                1)))
        (add-result 'body-begin)
        (signal C)
        (add-result 'body-normal-return))))

  (doit (make-error))
  ⇒ (1 (body-begin handler))

  (doit (make-warning))
  ⇒ (1 (body-begin handler))

  #| end of body |# )

;;Signalled condition, nested HANDLER-CASE uses.
;;
(internal-body

  (define (doit C)
    (with-result
      (handler-case
          ((&error   (lambda (E)
                       (add-result 'error-handler)
                       1)))
        (handler-case
            ((&warning (lambda (E)
                         (add-result 'warning-handler)
                         2)))
          (add-result 'body-begin)
          (signal C)
          (add-result 'body-normal-return)))))

  (doit (make-error))
  ⇒ (1 (body-begin error-handler))

  (doit (make-warning))
  ⇒ (2 (body-begin warning-handler))

  #| end of body |# )

(internal-body        ; unwind-protect

  (define (doit C)
    (with-result
      (handler-case
          ((&error   (lambda (E)
                       (add-result 'error-handler)
                       1)))
        (with-unwind-handler
            (lambda (why)
              (add-result 'outer-unwind-handler))
          (lambda ()
            (handler-case
                ((&warning (lambda (E)
                             (add-result 'warning-handler)
                             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
         inner-unwind-handler
         outer-unwind-handler
         error-handler))

  (doit (make-warning))
  ⇒ (2
        (body-begin
         inner-unwind-handler
         warning-handler
         outer-unwind-handler))

  #| end of body |# )

Next: , Previous: , Up: restarts   [Index]