annotate src/clojure/contrib/pprint/dispatch.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 ;; dispatch.clj -- part of the pretty printer for Clojure
rlm@10 2
rlm@10 3 ;; by Tom Faulhaber
rlm@10 4 ;; April 3, 2009
rlm@10 5
rlm@10 6 ; Copyright (c) Tom Faulhaber, Feb 2009. All rights reserved.
rlm@10 7 ; The use and distribution terms for this software are covered by the
rlm@10 8 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 9 ; which can be found in the file epl-v10.html at the root of this distribution.
rlm@10 10 ; By using this software in any fashion, you are agreeing to be bound by
rlm@10 11 ; the terms of this license.
rlm@10 12 ; You must not remove this notice, or any other, from this software.
rlm@10 13
rlm@10 14 ;; This module implements the default dispatch tables for pretty printing code and
rlm@10 15 ;; data.
rlm@10 16
rlm@10 17 (in-ns 'clojure.contrib.pprint)
rlm@10 18
rlm@10 19 (defn use-method
rlm@10 20 "Installs a function as a new method of multimethod associated with dispatch-value. "
rlm@10 21 [multifn dispatch-val func]
rlm@10 22 (. multifn addMethod dispatch-val func))
rlm@10 23
rlm@10 24 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 25 ;; Implementations of specific dispatch table entries
rlm@10 26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 27
rlm@10 28 ;;; Handle forms that can be "back-translated" to reader macros
rlm@10 29 ;;; Not all reader macros can be dealt with this way or at all.
rlm@10 30 ;;; Macros that we can't deal with at all are:
rlm@10 31 ;;; ; - The comment character is aborbed by the reader and never is part of the form
rlm@10 32 ;;; ` - Is fully processed at read time into a lisp expression (which will contain concats
rlm@10 33 ;;; and regular quotes).
rlm@10 34 ;;; ~@ - Also fully eaten by the processing of ` and can't be used outside.
rlm@10 35 ;;; , - is whitespace and is lost (like all other whitespace). Formats can generate commas
rlm@10 36 ;;; where they deem them useful to help readability.
rlm@10 37 ;;; ^ - Adding metadata completely disappears at read time and the data appears to be
rlm@10 38 ;;; completely lost.
rlm@10 39 ;;;
rlm@10 40 ;;; Most other syntax stuff is dealt with directly by the formats (like (), [], {}, and #{})
rlm@10 41 ;;; or directly by printing the objects using Clojure's built-in print functions (like
rlm@10 42 ;;; :keyword, \char, or ""). The notable exception is #() which is special-cased.
rlm@10 43
rlm@10 44 (def reader-macros
rlm@10 45 {'quote "'", 'clojure.core/deref "@",
rlm@10 46 'var "#'", 'clojure.core/unquote "~"})
rlm@10 47
rlm@10 48 (defn pprint-reader-macro [alis]
rlm@10 49 (let [^String macro-char (reader-macros (first alis))]
rlm@10 50 (when (and macro-char (= 2 (count alis)))
rlm@10 51 (.write ^java.io.Writer *out* macro-char)
rlm@10 52 (write-out (second alis))
rlm@10 53 true)))
rlm@10 54
rlm@10 55 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 56 ;; Dispatch for the basic data types when interpreted
rlm@10 57 ;; as data (as opposed to code).
rlm@10 58 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 59
rlm@10 60 ;;; TODO: inline these formatter statements into funcs so that we
rlm@10 61 ;;; are a little easier on the stack. (Or, do "real" compilation, a
rlm@10 62 ;;; la Common Lisp)
rlm@10 63
rlm@10 64 ;;; (def pprint-simple-list (formatter-out "~:<~@{~w~^ ~_~}~:>"))
rlm@10 65 (defn pprint-simple-list [alis]
rlm@10 66 (pprint-logical-block :prefix "(" :suffix ")"
rlm@10 67 (loop [alis (seq alis)]
rlm@10 68 (when alis
rlm@10 69 (write-out (first alis))
rlm@10 70 (when (next alis)
rlm@10 71 (.write ^java.io.Writer *out* " ")
rlm@10 72 (pprint-newline :linear)
rlm@10 73 (recur (next alis)))))))
rlm@10 74
rlm@10 75 (defn pprint-list [alis]
rlm@10 76 (if-not (pprint-reader-macro alis)
rlm@10 77 (pprint-simple-list alis)))
rlm@10 78
rlm@10 79 ;;; (def pprint-vector (formatter-out "~<[~;~@{~w~^ ~_~}~;]~:>"))
rlm@10 80 (defn pprint-vector [avec]
rlm@10 81 (pprint-logical-block :prefix "[" :suffix "]"
rlm@10 82 (loop [aseq (seq avec)]
rlm@10 83 (when aseq
rlm@10 84 (write-out (first aseq))
rlm@10 85 (when (next aseq)
rlm@10 86 (.write ^java.io.Writer *out* " ")
rlm@10 87 (pprint-newline :linear)
rlm@10 88 (recur (next aseq)))))))
rlm@10 89
rlm@10 90 (def pprint-array (formatter-out "~<[~;~@{~w~^, ~:_~}~;]~:>"))
rlm@10 91
rlm@10 92 ;;; (def pprint-map (formatter-out "~<{~;~@{~<~w~^ ~_~w~:>~^, ~_~}~;}~:>"))
rlm@10 93 (defn pprint-map [amap]
rlm@10 94 (pprint-logical-block :prefix "{" :suffix "}"
rlm@10 95 (loop [aseq (seq amap)]
rlm@10 96 (when aseq
rlm@10 97 (pprint-logical-block
rlm@10 98 (write-out (ffirst aseq))
rlm@10 99 (.write ^java.io.Writer *out* " ")
rlm@10 100 (pprint-newline :linear)
rlm@10 101 (write-out (fnext (first aseq))))
rlm@10 102 (when (next aseq)
rlm@10 103 (.write ^java.io.Writer *out* ", ")
rlm@10 104 (pprint-newline :linear)
rlm@10 105 (recur (next aseq)))))))
rlm@10 106
rlm@10 107 (def pprint-set (formatter-out "~<#{~;~@{~w~^ ~:_~}~;}~:>"))
rlm@10 108 (defn pprint-ref [ref]
rlm@10 109 (pprint-logical-block :prefix "#<Ref " :suffix ">"
rlm@10 110 (write-out @ref)))
rlm@10 111 (defn pprint-atom [ref]
rlm@10 112 (pprint-logical-block :prefix "#<Atom " :suffix ">"
rlm@10 113 (write-out @ref)))
rlm@10 114 (defn pprint-agent [ref]
rlm@10 115 (pprint-logical-block :prefix "#<Agent " :suffix ">"
rlm@10 116 (write-out @ref)))
rlm@10 117
rlm@10 118 (defn pprint-simple-default [obj]
rlm@10 119 (cond
rlm@10 120 (.isArray (class obj)) (pprint-array obj)
rlm@10 121 (and *print-suppress-namespaces* (symbol? obj)) (print (name obj))
rlm@10 122 :else (pr obj)))
rlm@10 123
rlm@10 124
rlm@10 125 (defmulti
rlm@10 126 *simple-dispatch*
rlm@10 127 "The pretty print dispatch function for simple data structure format."
rlm@10 128 {:arglists '[[object]]}
rlm@10 129 class)
rlm@10 130
rlm@10 131 (use-method *simple-dispatch* clojure.lang.ISeq pprint-list)
rlm@10 132 (use-method *simple-dispatch* clojure.lang.IPersistentVector pprint-vector)
rlm@10 133 (use-method *simple-dispatch* clojure.lang.IPersistentMap pprint-map)
rlm@10 134 (use-method *simple-dispatch* clojure.lang.IPersistentSet pprint-set)
rlm@10 135 (use-method *simple-dispatch* clojure.lang.Ref pprint-ref)
rlm@10 136 (use-method *simple-dispatch* clojure.lang.Atom pprint-atom)
rlm@10 137 (use-method *simple-dispatch* clojure.lang.Agent pprint-agent)
rlm@10 138 (use-method *simple-dispatch* nil pr)
rlm@10 139 (use-method *simple-dispatch* :default pprint-simple-default)
rlm@10 140
rlm@10 141 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 142 ;;; Dispatch for the code table
rlm@10 143 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 144
rlm@10 145 (declare pprint-simple-code-list)
rlm@10 146
rlm@10 147 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 148 ;;; Format something that looks like a simple def (sans metadata, since the reader
rlm@10 149 ;;; won't give it to us now).
rlm@10 150 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 151
rlm@10 152 (def pprint-hold-first (formatter-out "~:<~w~^ ~@_~w~^ ~_~@{~w~^ ~_~}~:>"))
rlm@10 153
rlm@10 154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 155 ;;; Format something that looks like a defn or defmacro
rlm@10 156 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 157
rlm@10 158 ;;; Format the params and body of a defn with a single arity
rlm@10 159 (defn- single-defn [alis has-doc-str?]
rlm@10 160 (if (seq alis)
rlm@10 161 (do
rlm@10 162 (if has-doc-str?
rlm@10 163 ((formatter-out " ~_"))
rlm@10 164 ((formatter-out " ~@_")))
rlm@10 165 ((formatter-out "~{~w~^ ~_~}") alis))))
rlm@10 166
rlm@10 167 ;;; Format the param and body sublists of a defn with multiple arities
rlm@10 168 (defn- multi-defn [alis has-doc-str?]
rlm@10 169 (if (seq alis)
rlm@10 170 ((formatter-out " ~_~{~w~^ ~_~}") alis)))
rlm@10 171
rlm@10 172 ;;; TODO: figure out how to support capturing metadata in defns (we might need a
rlm@10 173 ;;; special reader)
rlm@10 174 (defn pprint-defn [alis]
rlm@10 175 (if (next alis)
rlm@10 176 (let [[defn-sym defn-name & stuff] alis
rlm@10 177 [doc-str stuff] (if (string? (first stuff))
rlm@10 178 [(first stuff) (next stuff)]
rlm@10 179 [nil stuff])
rlm@10 180 [attr-map stuff] (if (map? (first stuff))
rlm@10 181 [(first stuff) (next stuff)]
rlm@10 182 [nil stuff])]
rlm@10 183 (pprint-logical-block :prefix "(" :suffix ")"
rlm@10 184 ((formatter-out "~w ~1I~@_~w") defn-sym defn-name)
rlm@10 185 (if doc-str
rlm@10 186 ((formatter-out " ~_~w") doc-str))
rlm@10 187 (if attr-map
rlm@10 188 ((formatter-out " ~_~w") attr-map))
rlm@10 189 ;; Note: the multi-defn case will work OK for malformed defns too
rlm@10 190 (cond
rlm@10 191 (vector? (first stuff)) (single-defn stuff (or doc-str attr-map))
rlm@10 192 :else (multi-defn stuff (or doc-str attr-map)))))
rlm@10 193 (pprint-simple-code-list alis)))
rlm@10 194
rlm@10 195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 196 ;;; Format something with a binding form
rlm@10 197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 198
rlm@10 199 (defn pprint-binding-form [binding-vec]
rlm@10 200 (pprint-logical-block :prefix "[" :suffix "]"
rlm@10 201 (loop [binding binding-vec]
rlm@10 202 (when (seq binding)
rlm@10 203 (pprint-logical-block binding
rlm@10 204 (write-out (first binding))
rlm@10 205 (when (next binding)
rlm@10 206 (.write ^java.io.Writer *out* " ")
rlm@10 207 (pprint-newline :miser)
rlm@10 208 (write-out (second binding))))
rlm@10 209 (when (next (rest binding))
rlm@10 210 (.write ^java.io.Writer *out* " ")
rlm@10 211 (pprint-newline :linear)
rlm@10 212 (recur (next (rest binding))))))))
rlm@10 213
rlm@10 214 (defn pprint-let [alis]
rlm@10 215 (let [base-sym (first alis)]
rlm@10 216 (pprint-logical-block :prefix "(" :suffix ")"
rlm@10 217 (if (and (next alis) (vector? (second alis)))
rlm@10 218 (do
rlm@10 219 ((formatter-out "~w ~1I~@_") base-sym)
rlm@10 220 (pprint-binding-form (second alis))
rlm@10 221 ((formatter-out " ~_~{~w~^ ~_~}") (next (rest alis))))
rlm@10 222 (pprint-simple-code-list alis)))))
rlm@10 223
rlm@10 224
rlm@10 225 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 226 ;;; Format something that looks like "if"
rlm@10 227 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 228
rlm@10 229 (def pprint-if (formatter-out "~:<~1I~w~^ ~@_~w~@{ ~_~w~}~:>"))
rlm@10 230
rlm@10 231 (defn pprint-cond [alis]
rlm@10 232 (pprint-logical-block :prefix "(" :suffix ")"
rlm@10 233 (pprint-indent :block 1)
rlm@10 234 (write-out (first alis))
rlm@10 235 (when (next alis)
rlm@10 236 (.write ^java.io.Writer *out* " ")
rlm@10 237 (pprint-newline :linear)
rlm@10 238 (loop [alis (next alis)]
rlm@10 239 (when alis
rlm@10 240 (pprint-logical-block alis
rlm@10 241 (write-out (first alis))
rlm@10 242 (when (next alis)
rlm@10 243 (.write ^java.io.Writer *out* " ")
rlm@10 244 (pprint-newline :miser)
rlm@10 245 (write-out (second alis))))
rlm@10 246 (when (next (rest alis))
rlm@10 247 (.write ^java.io.Writer *out* " ")
rlm@10 248 (pprint-newline :linear)
rlm@10 249 (recur (next (rest alis)))))))))
rlm@10 250
rlm@10 251 (defn pprint-condp [alis]
rlm@10 252 (if (> (count alis) 3)
rlm@10 253 (pprint-logical-block :prefix "(" :suffix ")"
rlm@10 254 (pprint-indent :block 1)
rlm@10 255 (apply (formatter-out "~w ~@_~w ~@_~w ~_") alis)
rlm@10 256 (loop [alis (seq (drop 3 alis))]
rlm@10 257 (when alis
rlm@10 258 (pprint-logical-block alis
rlm@10 259 (write-out (first alis))
rlm@10 260 (when (next alis)
rlm@10 261 (.write ^java.io.Writer *out* " ")
rlm@10 262 (pprint-newline :miser)
rlm@10 263 (write-out (second alis))))
rlm@10 264 (when (next (rest alis))
rlm@10 265 (.write ^java.io.Writer *out* " ")
rlm@10 266 (pprint-newline :linear)
rlm@10 267 (recur (next (rest alis)))))))
rlm@10 268 (pprint-simple-code-list alis)))
rlm@10 269
rlm@10 270 ;;; The map of symbols that are defined in an enclosing #() anonymous function
rlm@10 271 (def *symbol-map* {})
rlm@10 272
rlm@10 273 (defn pprint-anon-func [alis]
rlm@10 274 (let [args (second alis)
rlm@10 275 nlis (first (rest (rest alis)))]
rlm@10 276 (if (vector? args)
rlm@10 277 (binding [*symbol-map* (if (= 1 (count args))
rlm@10 278 {(first args) "%"}
rlm@10 279 (into {}
rlm@10 280 (map
rlm@10 281 #(vector %1 (str \% %2))
rlm@10 282 args
rlm@10 283 (range 1 (inc (count args))))))]
rlm@10 284 ((formatter-out "~<#(~;~@{~w~^ ~_~}~;)~:>") nlis))
rlm@10 285 (pprint-simple-code-list alis))))
rlm@10 286
rlm@10 287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 288 ;;; The master definitions for formatting lists in code (that is, (fn args...) or
rlm@10 289 ;;; special forms).
rlm@10 290 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
rlm@10 291
rlm@10 292 ;;; This is the equivalent of (formatter-out "~:<~1I~@{~w~^ ~_~}~:>"), but is
rlm@10 293 ;;; easier on the stack.
rlm@10 294
rlm@10 295 (defn pprint-simple-code-list [alis]
rlm@10 296 (pprint-logical-block :prefix "(" :suffix ")"
rlm@10 297 (pprint-indent :block 1)
rlm@10 298 (loop [alis (seq alis)]
rlm@10 299 (when alis
rlm@10 300 (write-out (first alis))
rlm@10 301 (when (next alis)
rlm@10 302 (.write ^java.io.Writer *out* " ")
rlm@10 303 (pprint-newline :linear)
rlm@10 304 (recur (next alis)))))))
rlm@10 305
rlm@10 306 ;;; Take a map with symbols as keys and add versions with no namespace.
rlm@10 307 ;;; That is, if ns/sym->val is in the map, add sym->val to the result.
rlm@10 308 (defn two-forms [amap]
rlm@10 309 (into {}
rlm@10 310 (mapcat
rlm@10 311 identity
rlm@10 312 (for [x amap]
rlm@10 313 [x [(symbol (name (first x))) (second x)]]))))
rlm@10 314
rlm@10 315 (defn add-core-ns [amap]
rlm@10 316 (let [core "clojure.core"]
rlm@10 317 (into {}
rlm@10 318 (map #(let [[s f] %]
rlm@10 319 (if (not (or (namespace s) (special-symbol? s)))
rlm@10 320 [(symbol core (name s)) f]
rlm@10 321 %))
rlm@10 322 amap))))
rlm@10 323
rlm@10 324 (def *code-table*
rlm@10 325 (two-forms
rlm@10 326 (add-core-ns
rlm@10 327 {'def pprint-hold-first, 'defonce pprint-hold-first,
rlm@10 328 'defn pprint-defn, 'defn- pprint-defn, 'defmacro pprint-defn, 'fn pprint-defn,
rlm@10 329 'let pprint-let, 'loop pprint-let, 'binding pprint-let,
rlm@10 330 'with-local-vars pprint-let, 'with-open pprint-let, 'when-let pprint-let,
rlm@10 331 'if-let pprint-let, 'doseq pprint-let, 'dotimes pprint-let,
rlm@10 332 'when-first pprint-let,
rlm@10 333 'if pprint-if, 'if-not pprint-if, 'when pprint-if, 'when-not pprint-if,
rlm@10 334 'cond pprint-cond, 'condp pprint-condp,
rlm@10 335 'fn* pprint-anon-func,
rlm@10 336 '. pprint-hold-first, '.. pprint-hold-first, '-> pprint-hold-first,
rlm@10 337 'locking pprint-hold-first, 'struct pprint-hold-first,
rlm@10 338 'struct-map pprint-hold-first,
rlm@10 339 })))
rlm@10 340
rlm@10 341 (defn pprint-code-list [alis]
rlm@10 342 (if-not (pprint-reader-macro alis)
rlm@10 343 (if-let [special-form (*code-table* (first alis))]
rlm@10 344 (special-form alis)
rlm@10 345 (pprint-simple-code-list alis))))
rlm@10 346
rlm@10 347 (defn pprint-code-symbol [sym]
rlm@10 348 (if-let [arg-num (sym *symbol-map*)]
rlm@10 349 (print arg-num)
rlm@10 350 (if *print-suppress-namespaces*
rlm@10 351 (print (name sym))
rlm@10 352 (pr sym))))
rlm@10 353
rlm@10 354 (defmulti
rlm@10 355 *code-dispatch*
rlm@10 356 "The pretty print dispatch function for pretty printing Clojure code."
rlm@10 357 {:arglists '[[object]]}
rlm@10 358 class)
rlm@10 359
rlm@10 360 (use-method *code-dispatch* clojure.lang.ISeq pprint-code-list)
rlm@10 361 (use-method *code-dispatch* clojure.lang.Symbol pprint-code-symbol)
rlm@10 362
rlm@10 363 ;; The following are all exact copies of *simple-dispatch*
rlm@10 364 (use-method *code-dispatch* clojure.lang.IPersistentVector pprint-vector)
rlm@10 365 (use-method *code-dispatch* clojure.lang.IPersistentMap pprint-map)
rlm@10 366 (use-method *code-dispatch* clojure.lang.IPersistentSet pprint-set)
rlm@10 367 (use-method *code-dispatch* clojure.lang.Ref pprint-ref)
rlm@10 368 (use-method *code-dispatch* clojure.lang.Atom pprint-atom)
rlm@10 369 (use-method *code-dispatch* clojure.lang.Agent pprint-agent)
rlm@10 370 (use-method *code-dispatch* nil pr)
rlm@10 371 (use-method *code-dispatch* :default pprint-simple-default)
rlm@10 372
rlm@10 373 (set-pprint-dispatch *simple-dispatch*)
rlm@10 374
rlm@10 375
rlm@10 376 ;;; For testing
rlm@10 377 (comment
rlm@10 378
rlm@10 379 (with-pprint-dispatch *code-dispatch*
rlm@10 380 (pprint
rlm@10 381 '(defn cl-format
rlm@10 382 "An implementation of a Common Lisp compatible format function"
rlm@10 383 [stream format-in & args]
rlm@10 384 (let [compiled-format (if (string? format-in) (compile-format format-in) format-in)
rlm@10 385 navigator (init-navigator args)]
rlm@10 386 (execute-format stream compiled-format navigator)))))
rlm@10 387
rlm@10 388 (with-pprint-dispatch *code-dispatch*
rlm@10 389 (pprint
rlm@10 390 '(defn cl-format
rlm@10 391 [stream format-in & args]
rlm@10 392 (let [compiled-format (if (string? format-in) (compile-format format-in) format-in)
rlm@10 393 navigator (init-navigator args)]
rlm@10 394 (execute-format stream compiled-format navigator)))))
rlm@10 395
rlm@10 396 (with-pprint-dispatch *code-dispatch*
rlm@10 397 (pprint
rlm@10 398 '(defn- -write
rlm@10 399 ([this x]
rlm@10 400 (condp = (class x)
rlm@10 401 String
rlm@10 402 (let [s0 (write-initial-lines this x)
rlm@10 403 s (.replaceFirst s0 "\\s+$" "")
rlm@10 404 white-space (.substring s0 (count s))
rlm@10 405 mode (getf :mode)]
rlm@10 406 (if (= mode :writing)
rlm@10 407 (dosync
rlm@10 408 (write-white-space this)
rlm@10 409 (.col_write this s)
rlm@10 410 (setf :trailing-white-space white-space))
rlm@10 411 (add-to-buffer this (make-buffer-blob s white-space))))
rlm@10 412
rlm@10 413 Integer
rlm@10 414 (let [c ^Character x]
rlm@10 415 (if (= (getf :mode) :writing)
rlm@10 416 (do
rlm@10 417 (write-white-space this)
rlm@10 418 (.col_write this x))
rlm@10 419 (if (= c (int \newline))
rlm@10 420 (write-initial-lines this "\n")
rlm@10 421 (add-to-buffer this (make-buffer-blob (str (char c)) nil))))))))))
rlm@10 422
rlm@10 423 (with-pprint-dispatch *code-dispatch*
rlm@10 424 (pprint
rlm@10 425 '(defn pprint-defn [writer alis]
rlm@10 426 (if (next alis)
rlm@10 427 (let [[defn-sym defn-name & stuff] alis
rlm@10 428 [doc-str stuff] (if (string? (first stuff))
rlm@10 429 [(first stuff) (next stuff)]
rlm@10 430 [nil stuff])
rlm@10 431 [attr-map stuff] (if (map? (first stuff))
rlm@10 432 [(first stuff) (next stuff)]
rlm@10 433 [nil stuff])]
rlm@10 434 (pprint-logical-block writer :prefix "(" :suffix ")"
rlm@10 435 (cl-format true "~w ~1I~@_~w" defn-sym defn-name)
rlm@10 436 (if doc-str
rlm@10 437 (cl-format true " ~_~w" doc-str))
rlm@10 438 (if attr-map
rlm@10 439 (cl-format true " ~_~w" attr-map))
rlm@10 440 ;; Note: the multi-defn case will work OK for malformed defns too
rlm@10 441 (cond
rlm@10 442 (vector? (first stuff)) (single-defn stuff (or doc-str attr-map))
rlm@10 443 :else (multi-defn stuff (or doc-str attr-map)))))
rlm@10 444 (pprint-simple-code-list writer alis)))))
rlm@10 445 )
rlm@10 446 nil
rlm@10 447