Mercurial > lasercutter
diff src/clojure/contrib/pprint/pprint_base.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/pprint/pprint_base.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,342 @@ 1.4 +;;; pprint_base.clj -- part of the pretty printer for Clojure 1.5 + 1.6 +;; by Tom Faulhaber 1.7 +;; April 3, 2009 1.8 + 1.9 +; Copyright (c) Tom Faulhaber, Jan 2009. All rights reserved. 1.10 +; The use and distribution terms for this software are covered by the 1.11 +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.12 +; which can be found in the file epl-v10.html at the root of this distribution. 1.13 +; By using this software in any fashion, you are agreeing to be bound by 1.14 +; the terms of this license. 1.15 +; You must not remove this notice, or any other, from this software. 1.16 + 1.17 +;; This module implements the generic pretty print functions and special variables 1.18 + 1.19 +(in-ns 'clojure.contrib.pprint) 1.20 + 1.21 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.22 +;; Variables that control the pretty printer 1.23 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.24 + 1.25 +;;; 1.26 +;;; *print-length*, *print-level* and *print-dup* are defined in clojure.core 1.27 +;;; TODO: use *print-dup* here (or is it supplanted by other variables?) 1.28 +;;; TODO: make dispatch items like "(let..." get counted in *print-length* 1.29 +;;; constructs 1.30 + 1.31 + 1.32 +(def 1.33 + ^{ :doc "Bind to true if you want write to use pretty printing"} 1.34 + *print-pretty* true) 1.35 + 1.36 +(defonce ; If folks have added stuff here, don't overwrite 1.37 + ^{ :doc "The pretty print dispatch function. Use with-pprint-dispatch or set-pprint-dispatch 1.38 +to modify."} 1.39 + *print-pprint-dispatch* nil) 1.40 + 1.41 +(def 1.42 + ^{ :doc "Pretty printing will try to avoid anything going beyond this column. 1.43 +Set it to nil to have pprint let the line be arbitrarily long. This will ignore all 1.44 +non-mandatory newlines."} 1.45 + *print-right-margin* 72) 1.46 + 1.47 +(def 1.48 + ^{ :doc "The column at which to enter miser style. Depending on the dispatch table, 1.49 +miser style add newlines in more places to try to keep lines short allowing for further 1.50 +levels of nesting."} 1.51 + *print-miser-width* 40) 1.52 + 1.53 +;;; TODO implement output limiting 1.54 +(def 1.55 + ^{ :doc "Maximum number of lines to print in a pretty print instance (N.B. This is not yet used)"} 1.56 + *print-lines* nil) 1.57 + 1.58 +;;; TODO: implement circle and shared 1.59 +(def 1.60 + ^{ :doc "Mark circular structures (N.B. This is not yet used)"} 1.61 + *print-circle* nil) 1.62 + 1.63 +;;; TODO: should we just use *print-dup* here? 1.64 +(def 1.65 + ^{ :doc "Mark repeated structures rather than repeat them (N.B. This is not yet used)"} 1.66 + *print-shared* nil) 1.67 + 1.68 +(def 1.69 + ^{ :doc "Don't print namespaces with symbols. This is particularly useful when 1.70 +pretty printing the results of macro expansions"} 1.71 + *print-suppress-namespaces* nil) 1.72 + 1.73 +;;; TODO: support print-base and print-radix in cl-format 1.74 +;;; TODO: support print-base and print-radix in rationals 1.75 +(def 1.76 + ^{ :doc "Print a radix specifier in front of integers and rationals. If *print-base* is 2, 8, 1.77 +or 16, then the radix specifier used is #b, #o, or #x, respectively. Otherwise the 1.78 +radix specifier is in the form #XXr where XX is the decimal value of *print-base* "} 1.79 + *print-radix* nil) 1.80 + 1.81 +(def 1.82 + ^{ :doc "The base to use for printing integers and rationals."} 1.83 + *print-base* 10) 1.84 + 1.85 + 1.86 + 1.87 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.88 +;; Internal variables that keep track of where we are in the 1.89 +;; structure 1.90 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.91 + 1.92 +(def ^{ :private true } *current-level* 0) 1.93 + 1.94 +(def ^{ :private true } *current-length* nil) 1.95 + 1.96 +;; TODO: add variables for length, lines. 1.97 + 1.98 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.99 +;; Support for the write function 1.100 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.101 + 1.102 +(declare format-simple-number) 1.103 + 1.104 +(def ^{:private true} orig-pr pr) 1.105 + 1.106 +(defn- pr-with-base [x] 1.107 + (if-let [s (format-simple-number x)] 1.108 + (print s) 1.109 + (orig-pr x))) 1.110 + 1.111 +(def ^{:private true} write-option-table 1.112 + {;:array *print-array* 1.113 + :base 'clojure.contrib.pprint/*print-base*, 1.114 + ;;:case *print-case*, 1.115 + :circle 'clojure.contrib.pprint/*print-circle*, 1.116 + ;;:escape *print-escape*, 1.117 + ;;:gensym *print-gensym*, 1.118 + :length 'clojure.core/*print-length*, 1.119 + :level 'clojure.core/*print-level*, 1.120 + :lines 'clojure.contrib.pprint/*print-lines*, 1.121 + :miser-width 'clojure.contrib.pprint/*print-miser-width*, 1.122 + :dispatch 'clojure.contrib.pprint/*print-pprint-dispatch*, 1.123 + :pretty 'clojure.contrib.pprint/*print-pretty*, 1.124 + :radix 'clojure.contrib.pprint/*print-radix*, 1.125 + :readably 'clojure.core/*print-readably*, 1.126 + :right-margin 'clojure.contrib.pprint/*print-right-margin*, 1.127 + :suppress-namespaces 'clojure.contrib.pprint/*print-suppress-namespaces*}) 1.128 + 1.129 + 1.130 +(defmacro ^{:private true} binding-map [amap & body] 1.131 + (let [] 1.132 + `(do 1.133 + (. clojure.lang.Var (pushThreadBindings ~amap)) 1.134 + (try 1.135 + ~@body 1.136 + (finally 1.137 + (. clojure.lang.Var (popThreadBindings))))))) 1.138 + 1.139 +(defn- table-ize [t m] 1.140 + (apply hash-map (mapcat 1.141 + #(when-let [v (get t (key %))] [(find-var v) (val %)]) 1.142 + m))) 1.143 + 1.144 +(defn- pretty-writer? 1.145 + "Return true iff x is a PrettyWriter" 1.146 + [x] (and (instance? clojure.lang.IDeref x) (:pretty-writer @@x))) 1.147 + 1.148 +(defn- make-pretty-writer 1.149 + "Wrap base-writer in a PrettyWriter with the specified right-margin and miser-width" 1.150 + [base-writer right-margin miser-width] 1.151 + (pretty-writer base-writer right-margin miser-width)) 1.152 + 1.153 +(defmacro ^{:private true} with-pretty-writer [base-writer & body] 1.154 + `(let [base-writer# ~base-writer 1.155 + new-writer# (not (pretty-writer? base-writer#))] 1.156 + (binding [*out* (if new-writer# 1.157 + (make-pretty-writer base-writer# *print-right-margin* *print-miser-width*) 1.158 + base-writer#)] 1.159 + ~@body 1.160 + (.flush *out*)))) 1.161 + 1.162 + 1.163 +;;;TODO: if pretty print is not set, don't use pr but rather something that respects *print-base*, etc. 1.164 +(defn write-out 1.165 + "Write an object to *out* subject to the current bindings of the printer control 1.166 +variables. Use the kw-args argument to override individual variables for this call (and 1.167 +any recursive calls). 1.168 + 1.169 +*out* must be a PrettyWriter if pretty printing is enabled. This is the responsibility 1.170 +of the caller. 1.171 + 1.172 +This method is primarily intended for use by pretty print dispatch functions that 1.173 +already know that the pretty printer will have set up their environment appropriately. 1.174 +Normal library clients should use the standard \"write\" interface. " 1.175 + [object] 1.176 + (let [length-reached (and 1.177 + *current-length* 1.178 + *print-length* 1.179 + (>= *current-length* *print-length*))] 1.180 + (if-not *print-pretty* 1.181 + (pr object) 1.182 + (if length-reached 1.183 + (print "...") 1.184 + (do 1.185 + (if *current-length* (set! *current-length* (inc *current-length*))) 1.186 + (*print-pprint-dispatch* object)))) 1.187 + length-reached)) 1.188 + 1.189 +(defn write 1.190 + "Write an object subject to the current bindings of the printer control variables. 1.191 +Use the kw-args argument to override individual variables for this call (and any 1.192 +recursive calls). Returns the string result if :stream is nil or nil otherwise. 1.193 + 1.194 +The following keyword arguments can be passed with values: 1.195 + Keyword Meaning Default value 1.196 + :stream Writer for output or nil true (indicates *out*) 1.197 + :base Base to use for writing rationals Current value of *print-base* 1.198 + :circle* If true, mark circular structures Current value of *print-circle* 1.199 + :length Maximum elements to show in sublists Current value of *print-length* 1.200 + :level Maximum depth Current value of *print-level* 1.201 + :lines* Maximum lines of output Current value of *print-lines* 1.202 + :miser-width Width to enter miser mode Current value of *print-miser-width* 1.203 + :dispatch The pretty print dispatch function Current value of *print-pprint-dispatch* 1.204 + :pretty If true, do pretty printing Current value of *print-pretty* 1.205 + :radix If true, prepend a radix specifier Current value of *print-radix* 1.206 + :readably* If true, print readably Current value of *print-readably* 1.207 + :right-margin The column for the right margin Current value of *print-right-margin* 1.208 + :suppress-namespaces If true, no namespaces in symbols Current value of *print-suppress-namespaces* 1.209 + 1.210 + * = not yet supported 1.211 +" 1.212 + [object & kw-args] 1.213 + (let [options (merge {:stream true} (apply hash-map kw-args))] 1.214 + (binding-map (table-ize write-option-table options) 1.215 + (binding-map (if (or (not (= *print-base* 10)) *print-radix*) {#'pr pr-with-base} {}) 1.216 + (let [optval (if (contains? options :stream) 1.217 + (:stream options) 1.218 + true) 1.219 + base-writer (condp = optval 1.220 + nil (java.io.StringWriter.) 1.221 + true *out* 1.222 + optval)] 1.223 + (if *print-pretty* 1.224 + (with-pretty-writer base-writer 1.225 + (write-out object)) 1.226 + (binding [*out* base-writer] 1.227 + (pr object))) 1.228 + (if (nil? optval) 1.229 + (.toString ^java.io.StringWriter base-writer))))))) 1.230 + 1.231 + 1.232 +(defn pprint 1.233 + "Pretty print object to the optional output writer. If the writer is not provided, 1.234 +print the object to the currently bound value of *out*." 1.235 + ([object] (pprint object *out*)) 1.236 + ([object writer] 1.237 + (with-pretty-writer writer 1.238 + (binding [*print-pretty* true] 1.239 + (binding-map (if (or (not (= *print-base* 10)) *print-radix*) {#'pr pr-with-base} {}) 1.240 + (write-out object))) 1.241 + (if (not (= 0 (get-column *out*))) 1.242 + (.write *out* (int \newline)))))) 1.243 + 1.244 +(defmacro pp 1.245 + "A convenience macro that pretty prints the last thing output. This is 1.246 +exactly equivalent to (pprint *1)." 1.247 + [] `(pprint *1)) 1.248 + 1.249 +(defn set-pprint-dispatch 1.250 + "Set the pretty print dispatch function to a function matching (fn [obj] ...) 1.251 +where obj is the object to pretty print. That function will be called with *out* set 1.252 +to a pretty printing writer to which it should do its printing. 1.253 + 1.254 +For example functions, see *simple-dispatch* and *code-dispatch* in 1.255 +clojure.contrib.pprint.dispatch.clj." 1.256 + [function] 1.257 + (let [old-meta (meta #'*print-pprint-dispatch*)] 1.258 + (alter-var-root #'*print-pprint-dispatch* (constantly function)) 1.259 + (alter-meta! #'*print-pprint-dispatch* (constantly old-meta))) 1.260 + nil) 1.261 + 1.262 +(defmacro with-pprint-dispatch 1.263 + "Execute body with the pretty print dispatch function bound to function." 1.264 + [function & body] 1.265 + `(binding [*print-pprint-dispatch* ~function] 1.266 + ~@body)) 1.267 + 1.268 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.269 +;; Support for the functional interface to the pretty printer 1.270 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.271 + 1.272 +(defn- parse-lb-options [opts body] 1.273 + (loop [body body 1.274 + acc []] 1.275 + (if (opts (first body)) 1.276 + (recur (drop 2 body) (concat acc (take 2 body))) 1.277 + [(apply hash-map acc) body]))) 1.278 + 1.279 +(defn- check-enumerated-arg [arg choices] 1.280 + (if-not (choices arg) 1.281 + (throw 1.282 + (IllegalArgumentException. 1.283 + ;; TODO clean up choices string 1.284 + (str "Bad argument: " arg ". It must be one of " choices))))) 1.285 + 1.286 +(defn level-exceeded [] 1.287 + (and *print-level* (>= *current-level* *print-level*))) 1.288 + 1.289 +(defmacro pprint-logical-block 1.290 + "Execute the body as a pretty printing logical block with output to *out* which 1.291 +must be a pretty printing writer. When used from pprint or cl-format, this can be 1.292 +assumed. 1.293 + 1.294 +Before the body, the caller can optionally specify options: :prefix, :per-line-prefix, 1.295 +and :suffix." 1.296 + {:arglists '[[options* body]]} 1.297 + [& args] 1.298 + (let [[options body] (parse-lb-options #{:prefix :per-line-prefix :suffix} args)] 1.299 + `(do (if (level-exceeded) 1.300 + (.write ^java.io.Writer *out* "#") 1.301 + (binding [*current-level* (inc *current-level*) 1.302 + *current-length* 0] 1.303 + (start-block *out* 1.304 + ~(:prefix options) ~(:per-line-prefix options) ~(:suffix options)) 1.305 + ~@body 1.306 + (end-block *out*))) 1.307 + nil))) 1.308 + 1.309 +(defn pprint-newline 1.310 + "Print a conditional newline to a pretty printing stream. kind specifies if the 1.311 +newline is :linear, :miser, :fill, or :mandatory. 1.312 + 1.313 +Output is sent to *out* which must be a pretty printing writer." 1.314 + [kind] 1.315 + (check-enumerated-arg kind #{:linear :miser :fill :mandatory}) 1.316 + (nl *out* kind)) 1.317 + 1.318 +(defn pprint-indent 1.319 + "Create an indent at this point in the pretty printing stream. This defines how 1.320 +following lines are indented. relative-to can be either :block or :current depending 1.321 +whether the indent should be computed relative to the start of the logical block or 1.322 +the current column position. n is an offset. 1.323 + 1.324 +Output is sent to *out* which must be a pretty printing writer." 1.325 + [relative-to n] 1.326 + (check-enumerated-arg relative-to #{:block :current}) 1.327 + (indent *out* relative-to n)) 1.328 + 1.329 +;; TODO a real implementation for pprint-tab 1.330 +(defn pprint-tab 1.331 + "Tab at this point in the pretty printing stream. kind specifies whether the tab 1.332 +is :line, :section, :line-relative, or :section-relative. 1.333 + 1.334 +Colnum and colinc specify the target column and the increment to move the target 1.335 +forward if the output is already past the original target. 1.336 + 1.337 +Output is sent to *out* which must be a pretty printing writer. 1.338 + 1.339 +THIS FUNCTION IS NOT YET IMPLEMENTED." 1.340 + [kind colnum colinc] 1.341 + (check-enumerated-arg kind #{:line :section :line-relative :section-relative}) 1.342 + (throw (UnsupportedOperationException. "pprint-tab is not yet implemented"))) 1.343 + 1.344 + 1.345 +nil