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