From 9103804aa60eacb2a294085e09f167e09779f338 Mon Sep 17 00:00:00 2001
From: Stuart Halloway <stu@thinkrelevance.com>
Date: Fri, 14 Oct 2011 13:46:57 -0400
Subject: [PATCH] CLJ-733 data conveying exception

---
 src/clj/clojure/core.clj                |    9 ++++++
 src/clj/clojure/main.clj                |    1 +
 src/clj/clojure/repl.clj                |    4 ++-
 src/jvm/clojure/lang/ExceptionInfo.java |   44 +++++++++++++++++++++++++++++++
 4 files changed, 57 insertions(+), 1 deletions(-)
 create mode 100644 src/jvm/clojure/lang/ExceptionInfo.java

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index b1801e9..1730400 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -4220,6 +4220,15 @@
     (with-out-str
      (apply println xs)))
 
+(import clojure.lang.ExceptionInfo)
+(defn ex-info
+  "Returns exception info (a map) if ex is an ExceptionInfo.
+   Otherwise returns nil"
+  {:added "1.4"}
+  [ex]
+  (when (instance? ExceptionInfo ex)
+    (.getData ^ExceptionInfo ex)))
+
 (defmacro assert
   "Evaluates expr and throws an exception if it does not evaluate to
   logical true."
diff --git a/src/clj/clojure/main.clj b/src/clj/clojure/main.clj
index 8efff8d..38d2b83 100644
--- a/src/clj/clojure/main.clj
+++ b/src/clj/clojure/main.clj
@@ -173,6 +173,7 @@
     (binding [*out* *err*]
       (println (str (-> ex class .getSimpleName)
                     " " (.getMessage ex) " "
+                    (when-let [info (ex-info ex)] (str info " "))
                     (when-not (instance? clojure.lang.Compiler$CompilerException ex)
                       (str " " (if el (stack-element-str el) "[trace missing]"))))))))
 
diff --git a/src/clj/clojure/repl.clj b/src/clj/clojure/repl.clj
index 3218180..f4dfced 100644
--- a/src/clj/clojure/repl.clj
+++ b/src/clj/clojure/repl.clj
@@ -251,7 +251,9 @@ str-or-pattern."
          (pst (root-cause e) e-or-depth))))
   ([^Throwable e depth]
      (binding [*out* *err*]
-       (println (str (-> e class .getSimpleName) " " (.getMessage e)))
+       (println (str (-> e class .getSimpleName) " "
+                     (.getMessage e)
+                     (when-let [info (ex-info e)] (str " " info))))
        (let [st (.getStackTrace e)
              cause (.getCause e)]
          (doseq [el (take depth
diff --git a/src/jvm/clojure/lang/ExceptionInfo.java b/src/jvm/clojure/lang/ExceptionInfo.java
new file mode 100644
index 0000000..19c00d3
--- /dev/null
+++ b/src/jvm/clojure/lang/ExceptionInfo.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) Rich Hickey. 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.
+ */
+
+package clojure.lang;
+
+import java.util.Map;
+
+/**
+ * Exception that carries data (a map) as additional payload. Clojure programs that need
+ * richer semantics for exceptions should use this in lieu of defining project-specific
+ * exception classes.
+ */
+public class ExceptionInfo extends RuntimeException{
+    public final IPersistentMap data;
+
+    public ExceptionInfo(IPersistentMap data) {
+        this.data = data;
+    }
+
+    public ExceptionInfo(IPersistentMap data, String s) {
+        super(s);
+        this.data = data;
+    }
+
+    public ExceptionInfo(IPersistentMap data, String s, Throwable throwable) {
+        super(s, throwable);
+        this.data = data;
+    }
+
+    public IPersistentMap getData() {
+        return data;
+    }
+
+    public String toString() {
+        return "clojure.lang.ExceptionInfo: " + getMessage() + " " + data.toString();
+    }
+}
-- 
1.7.4.1

