60 lines
2.1 KiB
Plaintext
60 lines
2.1 KiB
Plaintext
;;;; A condition type names its parent, and a handler for a type answers every
|
|
;;;; condition below it. Error is the root every built-in error descends from,
|
|
;;;; so one handler for it catches a bad index, an arithmetic failure and a
|
|
;;;; program's own error alike — and is handed the name and the runtime's
|
|
;;;; sentence, not the fields, since its type is the parent's.
|
|
|
|
;; A category: a parent with no field vector, which gets Error's two fields.
|
|
(defstruct IoError :parent Error)
|
|
(defstruct DiskFull :parent IoError [free i64])
|
|
;; A condition with no parent is matched by its own type and nothing else.
|
|
(defstruct Loner [n i32])
|
|
|
|
(defonce zero i64)
|
|
(defonce grid [4 i32])
|
|
|
|
(defn risky [n i32] i32
|
|
(cond
|
|
(= n 0) (i32 (/ 10 zero))
|
|
(= n 1) (at grid (+ n 5))
|
|
(= n 2) (do (error (DiskFull {.free 7})) 0)
|
|
:else n))
|
|
|
|
;; The catch-all. The clause runs after the unwind, so the name and the
|
|
;; sentence it prints are copies that outlived the frame that signalled.
|
|
(defn guarded [n i32] i32
|
|
(handler-case (risky n)
|
|
[(Error [e]
|
|
(println (.name e))
|
|
(println (.message e))
|
|
-1)]))
|
|
|
|
(defn main [] i32
|
|
(println (guarded 0))
|
|
(println (guarded 1))
|
|
(println (guarded 2))
|
|
(println (guarded 3))
|
|
;; A handler for the middle of the chain.
|
|
(println (handler-case (risky 2) [(IoError [e] (println (.name e)) -2)]))
|
|
;; A handler for the condition's own type still reads its fields, and is
|
|
;; the innermost, so it answers first.
|
|
(println
|
|
(handler-case
|
|
(handler-case (risky 2) [(DiskFull [d] (i32 (.free d)))])
|
|
[(Error [_e] -3)]))
|
|
;; A non-unwinding handler for Error sees the same two fields while the
|
|
;; signalling frame is alive, and the handler for ArithError inside it
|
|
;; reads the op as the enum it is.
|
|
(println
|
|
(handler-case
|
|
(handler-bind [(Error [e] (println (.message e)))]
|
|
(handler-bind [(ArithError [a] (println (= (.op a) :div-zero)))]
|
|
(risky 0)))
|
|
[(ArithError [_a] -4)]))
|
|
;; A condition outside the chain is not an Error.
|
|
(println
|
|
(handler-case
|
|
(handler-case (do (error (Loner {.n 1})) 0) [(Error [_e] -5)])
|
|
[(Loner [l] (.n l))]))
|
|
0)
|