Mercurial > lasercutter
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/pprint/dispatch.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,467 @@ 1.4 +;; dispatch.clj -- part of the pretty printer for Clojure 1.5 + 1.6 +; Copyright (c) Rich Hickey. All rights reserved. 1.7 +; The use and distribution terms for this software are covered by the 1.8 +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.9 +; which can be found in the file epl-v10.html at the root of this distribution. 1.10 +; By using this software in any fashion, you are agreeing to be bound by 1.11 +; the terms of this license. 1.12 +; You must not remove this notice, or any other, from this software. 1.13 + 1.14 +;; Author: Tom Faulhaber 1.15 +;; April 3, 2009 1.16 + 1.17 + 1.18 +;; This module implements the default dispatch tables for pretty printing code and 1.19 +;; data. 1.20 + 1.21 +(in-ns 'clojure.pprint) 1.22 + 1.23 +(defn- use-method 1.24 + "Installs a function as a new method of multimethod associated with dispatch-value. " 1.25 + [multifn dispatch-val func] 1.26 + (. multifn addMethod dispatch-val func)) 1.27 + 1.28 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.29 +;; Implementations of specific dispatch table entries 1.30 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.31 + 1.32 +;;; Handle forms that can be "back-translated" to reader macros 1.33 +;;; Not all reader macros can be dealt with this way or at all. 1.34 +;;; Macros that we can't deal with at all are: 1.35 +;;; ; - The comment character is aborbed by the reader and never is part of the form 1.36 +;;; ` - Is fully processed at read time into a lisp expression (which will contain concats 1.37 +;;; and regular quotes). 1.38 +;;; ~@ - Also fully eaten by the processing of ` and can't be used outside. 1.39 +;;; , - is whitespace and is lost (like all other whitespace). Formats can generate commas 1.40 +;;; where they deem them useful to help readability. 1.41 +;;; ^ - Adding metadata completely disappears at read time and the data appears to be 1.42 +;;; completely lost. 1.43 +;;; 1.44 +;;; Most other syntax stuff is dealt with directly by the formats (like (), [], {}, and #{}) 1.45 +;;; or directly by printing the objects using Clojure's built-in print functions (like 1.46 +;;; :keyword, \char, or ""). The notable exception is #() which is special-cased. 1.47 + 1.48 +(def ^{:private true} reader-macros 1.49 + {'quote "'", 'clojure.core/deref "@", 1.50 + 'var "#'", 'clojure.core/unquote "~"}) 1.51 + 1.52 +(defn- pprint-reader-macro [alis] 1.53 + (let [^String macro-char (reader-macros (first alis))] 1.54 + (when (and macro-char (= 2 (count alis))) 1.55 + (.write ^java.io.Writer *out* macro-char) 1.56 + (write-out (second alis)) 1.57 + true))) 1.58 + 1.59 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.60 +;; Dispatch for the basic data types when interpreted 1.61 +;; as data (as opposed to code). 1.62 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.63 + 1.64 +;;; TODO: inline these formatter statements into funcs so that we 1.65 +;;; are a little easier on the stack. (Or, do "real" compilation, a 1.66 +;;; la Common Lisp) 1.67 + 1.68 +;;; (def pprint-simple-list (formatter-out "~:<~@{~w~^ ~_~}~:>")) 1.69 +(defn- pprint-simple-list [alis] 1.70 + (pprint-logical-block :prefix "(" :suffix ")" 1.71 + (loop [alis (seq alis)] 1.72 + (when alis 1.73 + (write-out (first alis)) 1.74 + (when (next alis) 1.75 + (.write ^java.io.Writer *out* " ") 1.76 + (pprint-newline :linear) 1.77 + (recur (next alis))))))) 1.78 + 1.79 +(defn- pprint-list [alis] 1.80 + (if-not (pprint-reader-macro alis) 1.81 + (pprint-simple-list alis))) 1.82 + 1.83 +;;; (def pprint-vector (formatter-out "~<[~;~@{~w~^ ~_~}~;]~:>")) 1.84 +(defn- pprint-vector [avec] 1.85 + (pprint-logical-block :prefix "[" :suffix "]" 1.86 + (loop [aseq (seq avec)] 1.87 + (when aseq 1.88 + (write-out (first aseq)) 1.89 + (when (next aseq) 1.90 + (.write ^java.io.Writer *out* " ") 1.91 + (pprint-newline :linear) 1.92 + (recur (next aseq))))))) 1.93 + 1.94 +(def ^{:private true} pprint-array (formatter-out "~<[~;~@{~w~^, ~:_~}~;]~:>")) 1.95 + 1.96 +;;; (def pprint-map (formatter-out "~<{~;~@{~<~w~^ ~_~w~:>~^, ~_~}~;}~:>")) 1.97 +(defn- pprint-map [amap] 1.98 + (pprint-logical-block :prefix "{" :suffix "}" 1.99 + (loop [aseq (seq amap)] 1.100 + (when aseq 1.101 + (pprint-logical-block 1.102 + (write-out (ffirst aseq)) 1.103 + (.write ^java.io.Writer *out* " ") 1.104 + (pprint-newline :linear) 1.105 + (write-out (fnext (first aseq)))) 1.106 + (when (next aseq) 1.107 + (.write ^java.io.Writer *out* ", ") 1.108 + (pprint-newline :linear) 1.109 + (recur (next aseq))))))) 1.110 + 1.111 +(def ^{:private true} pprint-set (formatter-out "~<#{~;~@{~w~^ ~:_~}~;}~:>")) 1.112 + 1.113 +;;; TODO: don't block on promise (currently impossible) 1.114 + 1.115 +(def ^{:private true} 1.116 + type-map {"core$future_call" "Future", 1.117 + "core$promise" "Promise"}) 1.118 + 1.119 +(defn- map-ref-type 1.120 + "Map ugly type names to something simpler" 1.121 + [name] 1.122 + (or (when-let [match (re-find #"^[^$]+\$[^$]+" name)] 1.123 + (type-map match)) 1.124 + name)) 1.125 + 1.126 +(defn- pprint-ideref [o] 1.127 + (let [prefix (format "#<%s@%x%s: " 1.128 + (map-ref-type (.getSimpleName (class o))) 1.129 + (System/identityHashCode o) 1.130 + (if (and (instance? clojure.lang.Agent o) 1.131 + (agent-error o)) 1.132 + " FAILED" 1.133 + ""))] 1.134 + (pprint-logical-block :prefix prefix :suffix ">" 1.135 + (pprint-indent :block (-> (count prefix) (- 2) -)) 1.136 + (pprint-newline :linear) 1.137 + (write-out (cond 1.138 + (and (future? o) (not (future-done? o))) :pending 1.139 + :else @o))))) 1.140 + 1.141 +(def ^{:private true} pprint-pqueue (formatter-out "~<<-(~;~@{~w~^ ~_~}~;)-<~:>")) 1.142 + 1.143 +(defn- pprint-simple-default [obj] 1.144 + (cond 1.145 + (.isArray (class obj)) (pprint-array obj) 1.146 + (and *print-suppress-namespaces* (symbol? obj)) (print (name obj)) 1.147 + :else (pr obj))) 1.148 + 1.149 + 1.150 +(defmulti 1.151 + simple-dispatch 1.152 + "The pretty print dispatch function for simple data structure format." 1.153 + {:added "1.2" :arglists '[[object]]} 1.154 + class) 1.155 + 1.156 +(use-method simple-dispatch clojure.lang.ISeq pprint-list) 1.157 +(use-method simple-dispatch clojure.lang.IPersistentVector pprint-vector) 1.158 +(use-method simple-dispatch clojure.lang.IPersistentMap pprint-map) 1.159 +(use-method simple-dispatch clojure.lang.IPersistentSet pprint-set) 1.160 +(use-method simple-dispatch clojure.lang.PersistentQueue pprint-pqueue) 1.161 +(use-method simple-dispatch clojure.lang.IDeref pprint-ideref) 1.162 +(use-method simple-dispatch nil pr) 1.163 +(use-method simple-dispatch :default pprint-simple-default) 1.164 + 1.165 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.166 +;;; Dispatch for the code table 1.167 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.168 + 1.169 +(declare pprint-simple-code-list) 1.170 + 1.171 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.172 +;;; Format something that looks like a simple def (sans metadata, since the reader 1.173 +;;; won't give it to us now). 1.174 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.175 + 1.176 +(def ^{:private true} pprint-hold-first (formatter-out "~:<~w~^ ~@_~w~^ ~_~@{~w~^ ~_~}~:>")) 1.177 + 1.178 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.179 +;;; Format something that looks like a defn or defmacro 1.180 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.181 + 1.182 +;;; Format the params and body of a defn with a single arity 1.183 +(defn- single-defn [alis has-doc-str?] 1.184 + (if (seq alis) 1.185 + (do 1.186 + (if has-doc-str? 1.187 + ((formatter-out " ~_")) 1.188 + ((formatter-out " ~@_"))) 1.189 + ((formatter-out "~{~w~^ ~_~}") alis)))) 1.190 + 1.191 +;;; Format the param and body sublists of a defn with multiple arities 1.192 +(defn- multi-defn [alis has-doc-str?] 1.193 + (if (seq alis) 1.194 + ((formatter-out " ~_~{~w~^ ~_~}") alis))) 1.195 + 1.196 +;;; TODO: figure out how to support capturing metadata in defns (we might need a 1.197 +;;; special reader) 1.198 +(defn- pprint-defn [alis] 1.199 + (if (next alis) 1.200 + (let [[defn-sym defn-name & stuff] alis 1.201 + [doc-str stuff] (if (string? (first stuff)) 1.202 + [(first stuff) (next stuff)] 1.203 + [nil stuff]) 1.204 + [attr-map stuff] (if (map? (first stuff)) 1.205 + [(first stuff) (next stuff)] 1.206 + [nil stuff])] 1.207 + (pprint-logical-block :prefix "(" :suffix ")" 1.208 + ((formatter-out "~w ~1I~@_~w") defn-sym defn-name) 1.209 + (if doc-str 1.210 + ((formatter-out " ~_~w") doc-str)) 1.211 + (if attr-map 1.212 + ((formatter-out " ~_~w") attr-map)) 1.213 + ;; Note: the multi-defn case will work OK for malformed defns too 1.214 + (cond 1.215 + (vector? (first stuff)) (single-defn stuff (or doc-str attr-map)) 1.216 + :else (multi-defn stuff (or doc-str attr-map))))) 1.217 + (pprint-simple-code-list alis))) 1.218 + 1.219 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.220 +;;; Format something with a binding form 1.221 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.222 + 1.223 +(defn- pprint-binding-form [binding-vec] 1.224 + (pprint-logical-block :prefix "[" :suffix "]" 1.225 + (loop [binding binding-vec] 1.226 + (when (seq binding) 1.227 + (pprint-logical-block binding 1.228 + (write-out (first binding)) 1.229 + (when (next binding) 1.230 + (.write ^java.io.Writer *out* " ") 1.231 + (pprint-newline :miser) 1.232 + (write-out (second binding)))) 1.233 + (when (next (rest binding)) 1.234 + (.write ^java.io.Writer *out* " ") 1.235 + (pprint-newline :linear) 1.236 + (recur (next (rest binding)))))))) 1.237 + 1.238 +(defn- pprint-let [alis] 1.239 + (let [base-sym (first alis)] 1.240 + (pprint-logical-block :prefix "(" :suffix ")" 1.241 + (if (and (next alis) (vector? (second alis))) 1.242 + (do 1.243 + ((formatter-out "~w ~1I~@_") base-sym) 1.244 + (pprint-binding-form (second alis)) 1.245 + ((formatter-out " ~_~{~w~^ ~_~}") (next (rest alis)))) 1.246 + (pprint-simple-code-list alis))))) 1.247 + 1.248 + 1.249 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.250 +;;; Format something that looks like "if" 1.251 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.252 + 1.253 +(def ^{:private true} pprint-if (formatter-out "~:<~1I~w~^ ~@_~w~@{ ~_~w~}~:>")) 1.254 + 1.255 +(defn- pprint-cond [alis] 1.256 + (pprint-logical-block :prefix "(" :suffix ")" 1.257 + (pprint-indent :block 1) 1.258 + (write-out (first alis)) 1.259 + (when (next alis) 1.260 + (.write ^java.io.Writer *out* " ") 1.261 + (pprint-newline :linear) 1.262 + (loop [alis (next alis)] 1.263 + (when alis 1.264 + (pprint-logical-block alis 1.265 + (write-out (first alis)) 1.266 + (when (next alis) 1.267 + (.write ^java.io.Writer *out* " ") 1.268 + (pprint-newline :miser) 1.269 + (write-out (second alis)))) 1.270 + (when (next (rest alis)) 1.271 + (.write ^java.io.Writer *out* " ") 1.272 + (pprint-newline :linear) 1.273 + (recur (next (rest alis))))))))) 1.274 + 1.275 +(defn- pprint-condp [alis] 1.276 + (if (> (count alis) 3) 1.277 + (pprint-logical-block :prefix "(" :suffix ")" 1.278 + (pprint-indent :block 1) 1.279 + (apply (formatter-out "~w ~@_~w ~@_~w ~_") alis) 1.280 + (loop [alis (seq (drop 3 alis))] 1.281 + (when alis 1.282 + (pprint-logical-block alis 1.283 + (write-out (first alis)) 1.284 + (when (next alis) 1.285 + (.write ^java.io.Writer *out* " ") 1.286 + (pprint-newline :miser) 1.287 + (write-out (second alis)))) 1.288 + (when (next (rest alis)) 1.289 + (.write ^java.io.Writer *out* " ") 1.290 + (pprint-newline :linear) 1.291 + (recur (next (rest alis))))))) 1.292 + (pprint-simple-code-list alis))) 1.293 + 1.294 +;;; The map of symbols that are defined in an enclosing #() anonymous function 1.295 +(def ^{:private true} *symbol-map* {}) 1.296 + 1.297 +(defn- pprint-anon-func [alis] 1.298 + (let [args (second alis) 1.299 + nlis (first (rest (rest alis)))] 1.300 + (if (vector? args) 1.301 + (binding [*symbol-map* (if (= 1 (count args)) 1.302 + {(first args) "%"} 1.303 + (into {} 1.304 + (map 1.305 + #(vector %1 (str \% %2)) 1.306 + args 1.307 + (range 1 (inc (count args))))))] 1.308 + ((formatter-out "~<#(~;~@{~w~^ ~_~}~;)~:>") nlis)) 1.309 + (pprint-simple-code-list alis)))) 1.310 + 1.311 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.312 +;;; The master definitions for formatting lists in code (that is, (fn args...) or 1.313 +;;; special forms). 1.314 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.315 + 1.316 +;;; This is the equivalent of (formatter-out "~:<~1I~@{~w~^ ~_~}~:>"), but is 1.317 +;;; easier on the stack. 1.318 + 1.319 +(defn- pprint-simple-code-list [alis] 1.320 + (pprint-logical-block :prefix "(" :suffix ")" 1.321 + (pprint-indent :block 1) 1.322 + (loop [alis (seq alis)] 1.323 + (when alis 1.324 + (write-out (first alis)) 1.325 + (when (next alis) 1.326 + (.write ^java.io.Writer *out* " ") 1.327 + (pprint-newline :linear) 1.328 + (recur (next alis))))))) 1.329 + 1.330 +;;; Take a map with symbols as keys and add versions with no namespace. 1.331 +;;; That is, if ns/sym->val is in the map, add sym->val to the result. 1.332 +(defn- two-forms [amap] 1.333 + (into {} 1.334 + (mapcat 1.335 + identity 1.336 + (for [x amap] 1.337 + [x [(symbol (name (first x))) (second x)]])))) 1.338 + 1.339 +(defn- add-core-ns [amap] 1.340 + (let [core "clojure.core"] 1.341 + (into {} 1.342 + (map #(let [[s f] %] 1.343 + (if (not (or (namespace s) (special-symbol? s))) 1.344 + [(symbol core (name s)) f] 1.345 + %)) 1.346 + amap)))) 1.347 + 1.348 +(def ^{:private true} *code-table* 1.349 + (two-forms 1.350 + (add-core-ns 1.351 + {'def pprint-hold-first, 'defonce pprint-hold-first, 1.352 + 'defn pprint-defn, 'defn- pprint-defn, 'defmacro pprint-defn, 'fn pprint-defn, 1.353 + 'let pprint-let, 'loop pprint-let, 'binding pprint-let, 1.354 + 'with-local-vars pprint-let, 'with-open pprint-let, 'when-let pprint-let, 1.355 + 'if-let pprint-let, 'doseq pprint-let, 'dotimes pprint-let, 1.356 + 'when-first pprint-let, 1.357 + 'if pprint-if, 'if-not pprint-if, 'when pprint-if, 'when-not pprint-if, 1.358 + 'cond pprint-cond, 'condp pprint-condp, 1.359 + 'fn* pprint-anon-func, 1.360 + '. pprint-hold-first, '.. pprint-hold-first, '-> pprint-hold-first, 1.361 + 'locking pprint-hold-first, 'struct pprint-hold-first, 1.362 + 'struct-map pprint-hold-first, 1.363 + }))) 1.364 + 1.365 +(defn- pprint-code-list [alis] 1.366 + (if-not (pprint-reader-macro alis) 1.367 + (if-let [special-form (*code-table* (first alis))] 1.368 + (special-form alis) 1.369 + (pprint-simple-code-list alis)))) 1.370 + 1.371 +(defn- pprint-code-symbol [sym] 1.372 + (if-let [arg-num (sym *symbol-map*)] 1.373 + (print arg-num) 1.374 + (if *print-suppress-namespaces* 1.375 + (print (name sym)) 1.376 + (pr sym)))) 1.377 + 1.378 +(defmulti 1.379 + code-dispatch 1.380 + "The pretty print dispatch function for pretty printing Clojure code." 1.381 + {:added "1.2" :arglists '[[object]]} 1.382 + class) 1.383 + 1.384 +(use-method code-dispatch clojure.lang.ISeq pprint-code-list) 1.385 +(use-method code-dispatch clojure.lang.Symbol pprint-code-symbol) 1.386 + 1.387 +;; The following are all exact copies of simple-dispatch 1.388 +(use-method code-dispatch clojure.lang.IPersistentVector pprint-vector) 1.389 +(use-method code-dispatch clojure.lang.IPersistentMap pprint-map) 1.390 +(use-method code-dispatch clojure.lang.IPersistentSet pprint-set) 1.391 +(use-method code-dispatch clojure.lang.PersistentQueue pprint-pqueue) 1.392 +(use-method code-dispatch clojure.lang.IDeref pprint-ideref) 1.393 +(use-method code-dispatch nil pr) 1.394 +(use-method code-dispatch :default pprint-simple-default) 1.395 + 1.396 +(set-pprint-dispatch simple-dispatch) 1.397 + 1.398 + 1.399 +;;; For testing 1.400 +(comment 1.401 + 1.402 +(with-pprint-dispatch code-dispatch 1.403 + (pprint 1.404 + '(defn cl-format 1.405 + "An implementation of a Common Lisp compatible format function" 1.406 + [stream format-in & args] 1.407 + (let [compiled-format (if (string? format-in) (compile-format format-in) format-in) 1.408 + navigator (init-navigator args)] 1.409 + (execute-format stream compiled-format navigator))))) 1.410 + 1.411 +(with-pprint-dispatch code-dispatch 1.412 + (pprint 1.413 + '(defn cl-format 1.414 + [stream format-in & args] 1.415 + (let [compiled-format (if (string? format-in) (compile-format format-in) format-in) 1.416 + navigator (init-navigator args)] 1.417 + (execute-format stream compiled-format navigator))))) 1.418 + 1.419 +(with-pprint-dispatch code-dispatch 1.420 + (pprint 1.421 + '(defn- -write 1.422 + ([this x] 1.423 + (condp = (class x) 1.424 + String 1.425 + (let [s0 (write-initial-lines this x) 1.426 + s (.replaceFirst s0 "\\s+$" "") 1.427 + white-space (.substring s0 (count s)) 1.428 + mode (getf :mode)] 1.429 + (if (= mode :writing) 1.430 + (dosync 1.431 + (write-white-space this) 1.432 + (.col_write this s) 1.433 + (setf :trailing-white-space white-space)) 1.434 + (add-to-buffer this (make-buffer-blob s white-space)))) 1.435 + 1.436 + Integer 1.437 + (let [c ^Character x] 1.438 + (if (= (getf :mode) :writing) 1.439 + (do 1.440 + (write-white-space this) 1.441 + (.col_write this x)) 1.442 + (if (= c (int \newline)) 1.443 + (write-initial-lines this "\n") 1.444 + (add-to-buffer this (make-buffer-blob (str (char c)) nil)))))))))) 1.445 + 1.446 +(with-pprint-dispatch code-dispatch 1.447 + (pprint 1.448 + '(defn pprint-defn [writer alis] 1.449 + (if (next alis) 1.450 + (let [[defn-sym defn-name & stuff] alis 1.451 + [doc-str stuff] (if (string? (first stuff)) 1.452 + [(first stuff) (next stuff)] 1.453 + [nil stuff]) 1.454 + [attr-map stuff] (if (map? (first stuff)) 1.455 + [(first stuff) (next stuff)] 1.456 + [nil stuff])] 1.457 + (pprint-logical-block writer :prefix "(" :suffix ")" 1.458 + (cl-format true "~w ~1I~@_~w" defn-sym defn-name) 1.459 + (if doc-str 1.460 + (cl-format true " ~_~w" doc-str)) 1.461 + (if attr-map 1.462 + (cl-format true " ~_~w" attr-map)) 1.463 + ;; Note: the multi-defn case will work OK for malformed defns too 1.464 + (cond 1.465 + (vector? (first stuff)) (single-defn stuff (or doc-str attr-map)) 1.466 + :else (multi-defn stuff (or doc-str attr-map))))) 1.467 + (pprint-simple-code-list writer alis))))) 1.468 +) 1.469 +nil 1.470 +