diff options
author | scgilardi <scgilardi@gmail.com> | 2009-06-10 06:44:17 +0000 |
---|---|---|
committer | scgilardi <scgilardi@gmail.com> | 2009-06-10 06:44:17 +0000 |
commit | aa77176d5b020b0156bfaa88be4e9f13325bc634 (patch) | |
tree | 8154e306095e965157477efa1c194e9cdaad2768 /src | |
parent | e3aac22dd8eb5f638170934920dc7c16c7035dc4 (diff) |
add condition.clj: raise and handle conditions: maps
Diffstat (limited to 'src')
-rw-r--r-- | src/clojure/contrib/condition.clj | 77 | ||||
-rw-r--r-- | src/clojure/contrib/condition/Condition.clj | 31 |
2 files changed, 108 insertions, 0 deletions
diff --git a/src/clojure/contrib/condition.clj b/src/clojure/contrib/condition.clj new file mode 100644 index 00000000..fd80fb4b --- /dev/null +++ b/src/clojure/contrib/condition.clj @@ -0,0 +1,77 @@ +;; Copyright (c) Stephen C. Gilardi. All rights reserved. The use and +;; distribution terms for this software are covered by the Eclipse Public +;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can +;; be found in the file epl-v10.html at the root of this distribution. By +;; using this software in any fashion, you are agreeing to be bound by the +;; terms of this license. You must not remove this notice, or any other, +;; from this software. +;; +;; condition.clj +;; +;; Flexible raising and handling of conditions. A condition is a map +;; containing: +;; +;; - keys and values specified as arguments to raise, and +;; - a stack trace at key :stack-trace. +;; +;; Note: requires AOT compilation. +;; +;; scgilardi (gmail) +;; Created 09 June 2009 + +(ns + #^{:author "Stephen C. Gilardi", + :doc "Flexible raising and handling of conditions. A condition is a map +containing: + - keys and values specified as arguments to raise, and + - a stack trace at key :stack-trace. + +Note: requires AOT compilation."} + clojure.contrib.condition + (:require clojure.contrib.condition.Condition) + (:import clojure.contrib.condition.Condition)) + +(defmacro raise + "Raises a condition with the supplied mappings. + keyval => key val" + [& keyvals] + `(throw (Condition. (hash-map ~@keyvals)))) + +(defmacro handler-case + "Executes body in a context in which any raised conditions can be handled. + + dispatch-fn accepts a raised condition: a map, and returns a value used + to select a handler. + + The name specified by condition is bound to the condition within + handlers. + + Handlers are forms within body: + + (handle key + ...) + + If a condition is raised, executes the body of the first handler whose + key satisfies (isa? selector key). If no handlers match, the condition is + re-raised." + [dispatch-fn condition & body] + (let [selector (gensym "selector")] + (loop [[form & forms] body + m {:code [] :handlers []}] + (if form + (recur + forms + (if (and (list? form) (= (first form) 'handle)) + (let [[_ key & body] form + handler `[(isa? ~selector ~key) (do ~@body)]] + (update-in m [:handlers] concat handler)) + (update-in m [:code] conj form))) + (if (empty? (:handlers m)) + `(do ~@(:code m)) + `(try + ~@(:code m) + (catch Condition c# + (let [~condition (meta c#) + ~selector (~dispatch-fn ~condition)] + (cond ~@(:handlers m) + :else (throw c#)))))))))) diff --git a/src/clojure/contrib/condition/Condition.clj b/src/clojure/contrib/condition/Condition.clj new file mode 100644 index 00000000..b3a24340 --- /dev/null +++ b/src/clojure/contrib/condition/Condition.clj @@ -0,0 +1,31 @@ +;; Copyright (c) Stephen C. Gilardi. All rights reserved. The use and +;; distribution terms for this software are covered by the Eclipse Public +;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can +;; be found in the file epl-v10.html at the root of this distribution. By +;; using this software in any fashion, you are agreeing to be bound by the +;; terms of this license. You must not remove this notice, or any other, +;; from this software. +;; +;; Condition.clj +;; +;; Used by clojure.contrib.condition to implement a "Throwable map" +;; +;; scgilardi (gmail) +;; Created 09 June 2009 + +(ns clojure.contrib.condition.Condition + (:gen-class :extends Throwable + :implements [clojure.lang.IMeta] + :state _meta + :init init + :constructors + {[clojure.lang.IPersistentMap] []})) + +(defn -init + [meta] + [[] meta]) + +(defn -meta + [this] + (assoc (._meta this) + :stack-trace (into-array (drop 3 (.getStackTrace this))))) |