[alexandria-devel] UNWIND-PROTECT-CASE
Tobias C. Rittweiler
tcr at freebits.de
Sun Mar 9 12:25:18 UTC 2008
Sometimes it's desired to only do a certain cleanup operating in an
UNWIND-PROTECT if a true transfer-of-control was issued in the
protected-form.
UNWIND-PROTECT-CASE can be used to conveniently control on what
circumstances cleanup operations are supposed to be performed.
(I think I've seen UNWIND-PROTECT-CASE on one of the Lisp machines, so
it's actually prior art.)
-T.
(defmacro unwind-protect-case ((&optional abort-flag) protected-form &body clauses)
"Like CL:UNWIND-PROTECT, but you can specify the circumstances that
the cleanup CLAUSES are run.
ABORT-FLAG is the name of a variable that will be bound to T in
CLAUSES if the PROTECTED-FORM aborted preemptively, and to NIL
otherwise.
Examples:
(unwind-protect-case ()
(protected-form)
(:normal (format t \"This is only evaluated if PROTECTED-FORM executed normally.~%\"))
(:abort (format t \"This is only evaluated if PROTECTED-FORM aborted preemptively.~%\"))
(:always (format t \"This is evaluated in either case.~%\")))
(unwind-protect-case (aborted-p)
(protected-form)
(:always (perform-cleanup-if aborted-p)))
"
(check-type abort-flag (or null symbol))
(let ((gflag (gensym "FLAG+")))
`(let ((,gflag t))
(unwind-protect (multiple-value-prog1 ,protected-form (setf ,gflag nil))
(let ,(and abort-flag `((,abort-flag ,gflag)))
,@(loop for (cleanup-kind . forms) in clauses
collect (ecase cleanup-kind
(:normal `(when (not ,gflag) , at forms))
(:abort `(when ,gflag , at forms))
(:always `(progn , at forms)))))))))
More information about the alexandria-devel
mailing list