PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Clojure/Clojure/Bootstrap/core_print.clj

http://github.com/richhickey/clojure-clr
Clojure | 317 lines | 255 code | 52 blank | 10 comment | 42 complexity | 97fe779865efb5cfd2e8cb6938f9027c MD5 | raw file
Possible License(s): BSD-3-Clause
  1. ; Copyright (c) Rich Hickey. All rights reserved.
  2. ; The use and distribution terms for this software are covered by the
  3. ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  4. ; which can be found in the file epl-v10.html at the root of this distribution.
  5. ; By using this software in any fashion, you are agreeing to be bound by
  6. ; the terms of this license.
  7. ; You must not remove this notice, or any other, from this software.
  8. (in-ns 'clojure.core)
  9. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; printing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  10. (import '(System.IO.System.IO.TextWriter)) ;;; was (import '(java.io Writer)) (I have replaced #^Writer with #^System.IO.TextWriter throughout
  11. ;; Other global replaces: .write => .Write, .append => .Write, #^Class => #^Type, #^Character => #^Char
  12. (def
  13. #^{:doc "*print-length* controls how many items of each collection the
  14. printer will print. If it is bound to logical false, there is no
  15. limit. Otherwise, it must be bound to an integer indicating the maximum
  16. number of items of each collection to print. If a collection contains
  17. more items, the printer will print items up to the limit followed by
  18. '...' to represent the remaining items. The root binding is nil
  19. indicating no limit."}
  20. *print-length* nil)
  21. (def
  22. #^{:doc "*print-level* controls how many levels deep the printer will
  23. print nested objects. If it is bound to logical false, there is no
  24. limit. Otherwise, it must be bound to an integer indicating the maximum
  25. level to print. Each argument to print is at level 0; if an argument is a
  26. collection, its items are at level 1; and so on. If an object is a
  27. collection and is at a level greater than or equal to the value bound to
  28. *print-level*, the printer prints '#' to represent it. The root binding
  29. is nil indicating no limit."}
  30. *print-level* nil)
  31. (defn- print-sequential [#^String begin, print-one, #^String sep, #^String end, sequence, #^System.IO.TextWriter w]
  32. (binding [*print-level* (and (not *print-dup*) *print-level* (dec *print-level*))]
  33. (if (and *print-level* (neg? *print-level*))
  34. (.Write w "#")
  35. (do
  36. (.Write w begin)
  37. (when-let [xs (seq sequence)]
  38. (if (and (not *print-dup*) *print-length*)
  39. (loop [[x & xs] xs
  40. print-length *print-length*]
  41. (if (zero? print-length)
  42. (.Write w "...")
  43. (do
  44. (print-one x w)
  45. (when xs
  46. (.Write w sep)
  47. (recur xs (dec print-length))))))
  48. (loop [[x & xs] xs]
  49. (print-one x w)
  50. (when xs
  51. (.Write w sep)
  52. (recur xs)))))
  53. (.Write w end)))))
  54. (defn- print-meta [o, #^System.IO.TextWriter w]
  55. (when-let [m (meta o)]
  56. (when (and (pos? (count m))
  57. (or *print-dup*
  58. (and *print-meta* *print-readably*)))
  59. (.Write w "#^")
  60. (if (and (= (count m) 1) (:tag m))
  61. (pr-on (:tag m) w)
  62. (pr-on m w))
  63. (.Write w " "))))
  64. (defmethod print-method :default [o, #^System.IO.TextWriter w]
  65. (print-method (vary-meta o #(dissoc % :type)) w))
  66. (defmethod print-method nil [o, #^System.IO.TextWriter w]
  67. (.Write w "nil"))
  68. (defmethod print-dup nil [o w] (print-method o w))
  69. (defn print-ctor [o print-args #^System.IO.TextWriter w]
  70. (.Write w "#=(")
  71. (.Write w (.FullName #^Type (class o))) ;;; .getName => .FullName
  72. (.Write w ". ")
  73. (print-args o w)
  74. (.Write w ")"))
  75. (defmethod print-method Object [o, #^System.IO.TextWriter w]
  76. (.Write w "#<")
  77. (.Write w (.Name (class o))) ;;; .getSimpleName => .Name
  78. (.Write w " ")
  79. (.Write w (str o))
  80. (.Write w ">"))
  81. (defmethod print-method clojure.lang.Keyword [o, #^System.IO.TextWriter w]
  82. (.Write w (str o)))
  83. (defmethod print-dup clojure.lang.Keyword [o w] (print-method o w))
  84. ;;; MAJOR PROBLEM: no Number type in CLR. We will just ask every ValueType to print itself. Need to deal with BigDecimal and BigInteger later.
  85. (defmethod print-method ValueType [o, #^System.IO.TextWriter w] ;; Number => ValueType
  86. (.Write w (str o)))
  87. (defmethod print-dup ValueType [o, #^System.IO.TextWriter w] ;;; Number => ValueType
  88. (print-ctor o
  89. (fn [o w]
  90. (print-dup (str o) w))
  91. w))
  92. (defmethod print-dup clojure.lang.Fn [o, #^System.IO.TextWriter w]
  93. (print-ctor o (fn [o w]) w))
  94. (prefer-method print-dup clojure.lang.IPersistentCollection clojure.lang.Fn)
  95. (prefer-method print-dup java.util.Map clojure.lang.Fn)
  96. (prefer-method print-dup java.util.Collection clojure.lang.Fn)
  97. (defmethod print-method Boolean [o, #^System.IO.TextWriter w]
  98. (.Write w (str o)))
  99. (defmethod print-dup Boolean [o w] (print-method o w))
  100. (defn print-simple [o, #^System.IO.TextWriter w]
  101. (print-meta o w)
  102. (.Write w (str o)))
  103. (defmethod print-method clojure.lang.Symbol [o, #^System.IO.TextWriter w]
  104. (print-simple o w))
  105. (defmethod print-dup clojure.lang.Symbol [o w] (print-method o w))
  106. (defmethod print-method clojure.lang.Var [o, #^System.IO.TextWriter w]
  107. (print-simple o w))
  108. (defmethod print-dup clojure.lang.Var [#^clojure.lang.Var o, #^System.IO.TextWriter w]
  109. (.Write w (str "#=(var " (.Name (.ns o)) "/" (.Symbol o) ")"))) ;;; .name => .Name, .sym => .Symbol
  110. (defmethod print-method clojure.lang.ISeq [o, #^System.IO.TextWriter w]
  111. (print-meta o w)
  112. (print-sequential "(" pr-on " " ")" o w))
  113. (defmethod print-dup clojure.lang.ISeq [o w] (print-method o w))
  114. (defmethod print-dup clojure.lang.IPersistentList [o w] (print-method o w))
  115. (prefer-method print-method clojure.lang.IPersistentList clojure.lang.ISeq)
  116. (prefer-method print-dup clojure.lang.IPersistentList clojure.lang.ISeq)
  117. (prefer-method print-method clojure.lang.ISeq clojure.lang.IPersistentCollection)
  118. (prefer-method print-dup clojure.lang.ISeq clojure.lang.IPersistentCollection)
  119. (prefer-method print-method clojure.lang.ISeq System.Collections.ICollection) ;; java: java.util.Collection
  120. (prefer-method print-dup clojure.lang.ISeq System.Collections.ICollection) ;; java: java.util.Collection
  121. (defmethod print-method clojure.lang.IPersistentList [o, #^System.IO.TextWriter w]
  122. (print-meta o w)
  123. (print-sequential "(" print-method " " ")" o w))
  124. (defmethod print-dup System.Collections.ICollection [o, #^System.IO.TextWriter w] ;; java.util.Collection => System.Collections.ICollection
  125. (print-ctor o #(print-sequential "[" print-method " " "]" %1 %2) w))
  126. (defmethod print-dup clojure.lang.IPersistentCollection [o, #^System.IO.TextWriter w]
  127. (print-meta o w)
  128. (.Write w "#=(")
  129. (.Write w (.FullName #^Type (class o))) ;; .getName => .FullName
  130. (.Write w "/create ")
  131. (print-sequential "[" print-dup " " "]" o w)
  132. (.Write w ")"))
  133. (prefer-method print-dup clojure.lang.IPersistentCollection System.Collections.ICollection) ;; java.util.Collection => System.Collections.ICollection
  134. (def #^{:tag String
  135. :doc "Returns escape string for char or nil if none"}
  136. char-escape-string
  137. {\newline "\\n"
  138. \tab "\\t"
  139. \return "\\r"
  140. \" "\\\""
  141. \\ "\\\\"
  142. \formfeed "\\f"
  143. \backspace "\\b"})
  144. (defmethod print-method String [#^String s, #^System.IO.TextWriter w]
  145. (if (or *print-dup* *print-readably*)
  146. (do (.Write w \")
  147. (dotimes [n (count s)]
  148. (let [c (.get_Chars s n) ;; .charAt => .get_Chars
  149. e (char-escape-string c)]
  150. (if e (.Write w e) (.Write w c))))
  151. (.Write w \"))
  152. (.Write w s))
  153. nil)
  154. (defmethod print-dup String [s w] (print-method s w))
  155. (defmethod print-method clojure.lang.IPersistentVector [v, #^System.IO.TextWriter w]
  156. (print-meta v w)
  157. (print-sequential "[" pr-on " " "]" v w))
  158. (defn- print-map [m print-one w]
  159. (print-sequential
  160. "{"
  161. (fn [e #^System.IO.TextWriter w]
  162. (do (print-one (key e) w) (.Write w \space) (print-one (val e) w)))
  163. ", "
  164. "}"
  165. (seq m) w))
  166. (defmethod print-method clojure.lang.IPersistentMap [m, #^System.IO.TextWriter w]
  167. (print-meta m w)
  168. (print-map m pr-on w))
  169. (defmethod print-dup java.util.Map [m, #^System.IO.TextWriter w]
  170. (print-ctor m #(print-map (seq %1) print-method %2) w))
  171. (defmethod print-dup clojure.lang.IPersistentMap [m, #^System.IO.TextWriter w]
  172. (print-meta m w)
  173. (.Write w "#=(")
  174. (.Write w (.FullName (class m))) ;; .getName => .FullName
  175. (.Write w "/create ")
  176. (print-map m print-dup w)
  177. (.Write w ")"))
  178. (prefer-method print-dup clojure.lang.IPersistentMap System.Collections.IDictionary) ;; java.util.Map -> System.Collections.IDictionary
  179. (defmethod print-method clojure.lang.IPersistentSet [s, #^System.IO.TextWriter w]
  180. (print-meta s w)
  181. (print-sequential "#{" pr-on " " "}" (seq s) w))
  182. (def #^{:tag String
  183. :doc "Returns name string for char or nil if none"}
  184. char-name-string
  185. {\newline "newline"
  186. \tab "tab"
  187. \space "space"
  188. \backspace "backspace"
  189. \formfeed "formfeed"
  190. \return "return"})
  191. (defmethod print-method Char [#^Char c, #^System.IO.TextWriter w]
  192. (if (or *print-dup* *print-readably*)
  193. (do (.Write w \\)
  194. (let [n (char-name-string c)]
  195. (if n (.Write w n) (.Write w c))))
  196. (.Write w c))
  197. nil)
  198. (defmethod print-dup Char [c w] (print-method c w)) ;;; java.lang.Character
  199. (defmethod print-dup Int32 [o w] (print-method o w)) ;;; java.lang.Integer
  200. (defmethod print-dup Double [o w] (print-method o w)) ;;; java.lang.Double
  201. (defmethod print-dup clojure.lang.Ratio [o w] (print-method o w))
  202. (defmethod print-dup java.math.BigDecimal [o w] (print-method o w))
  203. (defmethod print-dup clojure.lang.PersistentHashMap [o w] (print-method o w))
  204. (defmethod print-dup clojure.lang.PersistentHashSet [o w] (print-method o w))
  205. (defmethod print-dup clojure.lang.PersistentVector [o w] (print-method o w))
  206. (defmethod print-dup clojure.lang.LazilyPersistentVector [o w] (print-method o w))
  207. (def primitives-classnames ;; not clear what the equiv should be
  208. {Single "Single" ;;{Float/TYPE "Float/TYPE"
  209. Int32 "Int32" ;; Integer/TYPE "Integer/TYPE"
  210. Int64 "Int64" ;; Long/TYPE "Long/TYPE"
  211. Boolean "Boolean" ;; Boolean/TYPE "Boolean/TYPE"
  212. Char "Char" ;; Character/TYPE "Character/TYPE"
  213. Double "Double" ;; Double/TYPE "Double/TYPE"
  214. Byte "Byte" ;; Byte/TYPE "Byte/TYPE"
  215. Int16 "Int16"}) ;; Short/TYPE "Short/TYPE"})
  216. (defmethod print-method Type [#^Type c, #^System.IO.TextWriter w]
  217. (.Write w (.FullName c))) ;;; .getName => .FullName
  218. (defmethod print-dup Type [#^Type c, #^System.IO.TextWriter w]
  219. (cond
  220. (.IsPrimitive c) (do ;; .isPrimitive
  221. (.Write w "#=(identity ")
  222. (.Write w #^String (primitives-classnames c))
  223. (.Write w ")"))
  224. (.IsArray c) (do ;; .isArray , java.lang.Class/forName =>
  225. (.Write w "#=(clojure.lang.RT/classForName \"")
  226. (.Write w (.FullName c)) ;; .getName => .FullName
  227. (.Write w "\")"))
  228. :else (do
  229. (.Write w "#=")
  230. (.Write w (.FullName c))))) ;;; .getName => .FullName
  231. (defmethod print-method java.math.BigDecimal [b, #^System.IO.TextWriter w]
  232. (.Write w (str b))
  233. (.Write w "M"))
  234. (defmethod print-method System.Text.RegularExpressions.Regex [p #^System.IO.TextWriter w] ;;; java.util.regex.Pattern =>
  235. (.Write w "#\"")
  236. (loop [[#^Char c & r :as s] (seq (.ToString #^System.Text.RegularExpressions.Regex p)) ;;; .pattern => .ToString
  237. qmode false]
  238. (when s
  239. (cond
  240. (= c \\) (let [[#^Char c2 & r2] r]
  241. (.Write w \\)
  242. (.Write w c2)
  243. (if qmode
  244. (recur r2 (not= c2 \E))
  245. (recur r2 (= c2 \Q))))
  246. (= c \") (do
  247. (if qmode
  248. (.Write w "\\E\\\"\\Q")
  249. (.Write w "\\\""))
  250. (recur r qmode))
  251. :else (do
  252. (.Write w c)
  253. (recur r qmode)))))
  254. (.Write w \"))
  255. (defmethod print-dup System.Text.RegularExpressions.Regex [p #^System.IO.TextWriter w] (print-method p w)) ;;; java.util.regex.Pattern =>
  256. (defmethod print-dup clojure.lang.Namespace [#^clojure.lang.Namespace n #^System.IO.TextWriter w]
  257. (.Write w "#=(find-ns ")
  258. (print-dup (.Name n) w) ;; .name
  259. (.Write w ")"))
  260. (defmethod print-method clojure.lang.IDeref [o #^System.IO.TextWriter w]
  261. (print-sequential (format "#<%s@%x: "
  262. (.Name (class o)) ;;; .getSimpleName => .Name
  263. (.GetHashCode o)) ;;; No easy equivelent in CLR: (System/identityHashCode o)))
  264. pr-on, "", ">", (list (if (and (future? o) (not (future-done? o))) :pending @o)), w))
  265. (def #^{:private true} print-initialized true)