0.7.4.3:
[sbcl.git] / src / code / describe.lisp
1 ;;;; most of the DESCRIBE mechanism -- that part which isn't derived
2 ;;;; from PCL code
3
4 ;;;; This software is part of the SBCL system. See the README file for
5 ;;;; more information.
6 ;;;;
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
12
13 (in-package "SB-IMPL") ;(SB-IMPL, not SB!IMPL, since we're built in warm load.)
14 \f
15 (declaim (ftype (function (t stream)) describe-object))
16 (defgeneric describe-object ((x t) stream))
17
18 (defun describe (x &optional (stream-designator *standard-output*))
19   #+sb-doc
20   "Print a description of the object X."
21   (let ((stream (out-synonym-of stream-designator)))
22     (fresh-line stream)
23     (pprint-logical-block (stream nil)
24       (describe-object x stream)
25       (pprint-newline :mandatory stream)))
26   (values))
27 \f
28 ;;;; miscellaneous DESCRIBE-OBJECT methods
29
30 (defmethod describe-object ((x t) s)
31   (format s "~@<~S ~_is a ~S.~:>" x (type-of x)))
32
33 (defmethod describe-object ((x cons) s)
34   (call-next-method)
35   (when (and (legal-fun-name-p x)
36              (fboundp x))
37     (%describe-fun (fdefinition x) s :function x)
38     ;;was: (format s "~@:_Its FDEFINITION is ~S.~@:_" (fdefinition x))
39     ;; TO DO: should check for SETF documentation.
40     ;; TO DO: should make it clear whether the definition is a
41     ;; DEFUN (SETF FOO) or DEFSETF FOO or what.
42     ))
43
44 (defmethod describe-object ((x array) s)
45   (let ((rank (array-rank x)))
46     (cond ((> rank 1)
47            (format s "~S ~_is " x)
48            (write-string (if (%array-displaced-p x) "a displaced" "an") s)
49            (format s " array of rank ~S." rank)
50            (format s "~@:_Its dimensions are ~S." (array-dimensions x)))
51           (t
52            (format s
53                    "~@:_~S is a ~:[~;displaced ~]vector of length ~S." x
54                    (and (array-header-p x) (%array-displaced-p x)) (length x))
55            (when (array-has-fill-pointer-p x)
56              (format s "~@:_It has a fill pointer, currently ~S."
57                      (fill-pointer x))))))
58   (let ((array-element-type (array-element-type x)))
59     (unless (eq array-element-type t)
60       (format s
61               "~@:_Its element type is specialized to ~S."
62               array-element-type))))
63
64 (defmethod describe-object ((x hash-table) s)
65   (declare (type stream s))
66   (format s "~@<~S ~_is an ~S hash table.~:>" x (hash-table-test x))
67   (format s "~_Its SIZE is ~S." (hash-table-size x))
68   (format s
69           "~@:_~@<Its REHASH-SIZE is ~S. ~_Its REHASH-THRESHOLD is ~S.~:>"
70           (hash-table-rehash-size x)
71           (hash-table-rehash-threshold x))
72   (let ((count (hash-table-count x)))
73     (format s "~@:_It holds ~S key/value pair~:P~:[: ~2I~_~;.~]"
74             count (zerop count))
75     (let ((n 0))
76       (declare (type index n))
77       (dohash (k v x)
78         (unless (zerop n)
79           (write-char #\space s))
80         (incf n)
81         (when (and *print-length* (> n *print-length*))
82           (format s "~:_...")
83           (return))
84         (format s "~:_(~@<~S ~:_~S~:>)" k v)))))
85
86 (defmethod describe-object ((condition condition) s)
87   (sb-kernel:describe-condition condition s))
88 \f
89 ;;;; DESCRIBE-OBJECT methods for symbols and functions, including all
90 ;;;; sorts of messy stuff about documentation, type information,
91 ;;;; packaging, function implementation, etc..
92
93 ;;; Print the specified kind of documentation about the given NAME. If
94 ;;; NAME is null, or not a valid name, then don't print anything.
95 (declaim (ftype (function (t stream t t) (values)) %describe-doc))
96 (defun %describe-doc (name s kind kind-doc)
97   (when (and name (typep name '(or symbol cons)))
98     (let ((doc (fdocumentation name kind)))
99       (when doc
100         (format s "~_~@(~A documentation:~)~@:_  ~A"
101                 (or kind-doc kind) doc))))
102   (values))
103
104 ;;; Describe various stuff about the functional semantics attached to
105 ;;; the specified NAME, if NAME is the kind of thing you can look
106 ;;; up as a name. (In the case of anonymous closures and other
107 ;;; things, it might not be.) TYPE-SPEC is the function type specifier
108 ;;; extracted from the definition, or NIL if none.
109 (declaim (ftype (function (t stream t)) %describe-fun-name))
110 (defun %describe-fun-name (name s type-spec) 
111   (when (and name (typep name '(or symbol cons)))
112     (multiple-value-bind (type where)
113         (if (or (symbolp name) (and (listp name) (eq (car name) 'setf)))
114             (values (type-specifier (info :function :type name))
115                     (info :function :where-from name))
116             (values type-spec :defined))
117       (when (consp type)
118         (format s "~@:_Its ~(~A~) argument types are:~@:_  ~S"
119                 where (second type))
120         (format s "~@:_Its result type is:~@:_  ~S" (third type))))
121     (let ((inlinep (info :function :inlinep name)))
122       (when inlinep
123         (format s
124                 "~@:_It is currently declared ~(~A~);~
125                  ~:[no~;~] expansion is available."
126                 inlinep (info :function :inline-expansion-designator name))))))
127
128 ;;; Print information from the debug-info about where CODE-OBJ was
129 ;;; compiled from.
130 (defun %describe-compiled-from (code-obj s)
131   (declare (type stream s))
132   (let ((info (sb-kernel:%code-debug-info code-obj)))
133     (when info
134       (let ((sources (sb-c::debug-info-source info)))
135         (when sources
136           (format s "~@:_On ~A it was compiled from:"
137                   ;; FIXME: The FORMAT-UNIVERSAL-TIME calls in the system
138                   ;; should become more consistent, probably not using
139                   ;; any nondefault options.
140                   (format-universal-time nil
141                                          (sb-c::debug-source-compiled
142                                           (first sources))
143                                          :style :abbreviated))
144           (dolist (source sources)
145             (let ((name (sb-c::debug-source-name source)))
146               (ecase (sb-c::debug-source-from source)
147                 (:file
148                  (format s "~@:_~A~@:_  Created: " (namestring name))
149                  (format-universal-time s (sb-c::debug-source-created
150                                            source)))
151                 (:lisp (format s "~@:_~S" name))))))))))
152
153 ;;; Describe a compiled function. The closure case calls us to print
154 ;;; the guts.
155 (defun %describe-fun-compiled (x s kind name)
156   (declare (type stream s))
157   (let ((args (%simple-fun-arglist x)))
158     (cond ((not args)
159            (write-string "  There are no arguments." s))
160           (t
161            (format s "~@:_~@(The ~@[~A's ~]arguments are:~@:_~)" kind)
162            (write-string "  " s)
163             (let ((*print-pretty* t)
164                   (*print-escape* t)
165                   (*print-base* 10)
166                   (*print-radix* nil))
167               (pprint-logical-block (s nil)
168                  (pprint-indent :current 2)
169                  (format s "~A" args))))))
170   (let ((name (or name (%simple-fun-name x))))
171     (%describe-doc name s 'function kind)
172     (unless (eq kind :macro)
173       (%describe-fun-name name s (%simple-fun-type x))))
174   (%describe-compiled-from (sb-kernel:fun-code-header x) s))
175
176 ;;; Describe a function object. KIND and NAME provide some information
177 ;;; about where the function came from.
178 (defun %describe-fun (x s &optional (kind :function) (name nil))
179   (declare (type function x))
180   (declare (type stream s))
181   (declare (type (member :macro :function) kind))
182   (fresh-line s)
183   (ecase kind
184     (:macro (format s "Macro-function: ~S" x))
185     (:function (if name
186                    (format s "Function: ~S" x)
187                    (format s "~S is a function." x))))
188   (format s "~@:_Its associated name (as in ~S) is ~S."
189           'function-lambda-expression
190           (%fun-name x))
191   (case (widetag-of x)
192     (#.sb-vm:closure-header-widetag
193      (%describe-fun-compiled (%closure-fun x) s kind name)
194      (format s "~@:_Its closure environment is:")
195      (pprint-logical-block (s nil)
196        (pprint-indent :current 8)
197        (dotimes (i (- (get-closure-length x) (1- sb-vm:closure-info-offset)))
198          (format s "~@:_~S: ~S" i (%closure-index-ref x i)))))
199     ((#.sb-vm:simple-fun-header-widetag #.sb-vm:closure-fun-header-widetag)
200      (%describe-fun-compiled x s kind name))
201     (#.sb-vm:funcallable-instance-header-widetag
202      ;; Only STANDARD-GENERIC-FUNCTION would be handled here, but
203      ;; since it has its own DESCRIBE-OBJECT method, it should've been
204      ;; picked off before getting here. So hopefully we never get here.
205      (format s "~@:_It is an unknown type of funcallable instance."))
206     (t
207      (format s "~@:_It is an unknown type of function."))))
208
209 (defmethod describe-object ((x function) s)
210   (%describe-fun x s :function))
211
212 (defgeneric describe-symbol-fdefinition (function stream &key (name nil) ))
213
214 (defmethod describe-symbol-fdefinition ((fun function) stream &key name)
215   (%describe-fun fun stream :function name))
216
217 (defmethod describe-symbol-fdefinition ((fun standard-generic-function) stream
218                                         &key name)
219   (declare (ignore name))
220   ;; just delegate
221   (describe-object fun stream))
222
223 (defmethod describe-object ((x symbol) s)
224   (declare (type stream s))
225
226   ;; Describe the packaging.
227   (let ((package (symbol-package x)))
228     (if package
229         (multiple-value-bind (symbol status)
230             (find-symbol (symbol-name x) package)
231           (declare (ignore symbol))
232           (format s "~@<~S is ~_an ~(~A~) symbol ~_in ~S.~:>"
233                   x status (symbol-package x)))
234         (format s "~@<~S is ~_an uninterned symbol.~:>" x)))
235   ;; TO DO: We could grovel over all packages looking for and
236   ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
237   ;; availability in some package even after (SYMBOL-PACKAGE X) has
238   ;; been set to NIL.
239
240   ;; Describe the value cell.
241   (let* ((kind (info :variable :kind x))
242          (wot (ecase kind
243                 (:special "special variable")
244                 (:macro "symbol macro")
245                 (:constant "constant")
246                 (:global "undefined variable")
247                 (:alien nil))))
248     (cond
249      ((eq kind :alien)
250       (let ((info (info :variable :alien-info x)))
251         (format s "~@:_~@<It is an alien at #X~8,'0X of type ~3I~:_~S.~:>~@:_"
252                 (sap-int (eval (sb-alien::heap-alien-info-sap-form info)))
253                 (sb-alien-internals:unparse-alien-type
254                  (sb-alien::heap-alien-info-type info)))
255         (format s "~@<Its current value is ~3I~:_~S.~:>"
256                 (eval x))))
257      ((eq kind :macro)
258       (let ((expansion (info :variable :macro-expansion x)))
259         (format s "~@:_It is a ~A with expansion ~S." wot expansion)))
260      ((boundp x)
261       (format s "~@:_~@<It is a ~A; its ~_value is ~S.~:>"
262               wot (symbol-value x)))
263      ((not (eq kind :global))
264       (format s "~@:_~@<It is a ~A; no current value.~:>" wot)))
265
266     (when (eq (info :variable :where-from x) :declared)
267       (format s "~@:_~@<Its declared type ~_is ~S.~:>"
268               (type-specifier (info :variable :type x))))
269
270     (%describe-doc x s 'variable kind))
271
272   ;; Print out properties.
273   (format s "~@[~@:_Its SYMBOL-PLIST is ~@<~2I~_~S~:>.~]" (symbol-plist x))
274
275   ;; Describe the function cell.
276   (cond ((macro-function x)
277          (%describe-fun (macro-function x) s :macro x))
278         ((special-operator-p x)
279          (%describe-doc x s :function "Special form"))
280         ((fboundp x)
281          (describe-symbol-fdefinition (fdefinition x) s :name x)))
282
283   ;; Print other documentation.
284   (%describe-doc x s 'structure "Structure")
285   (%describe-doc x s 'type "Type")
286   (%describe-doc x s 'setf "Setf macro")
287   (dolist (assoc (info :random-documentation :stuff x))
288     (format s
289             "~@:_Documentation on the ~(~A~):~@:_~A"
290             (car assoc)
291             (cdr assoc)))
292   
293   ;; Mention the associated type information, if any.
294   ;;
295   ;; As of sbcl-0.7.2, (INFO :TYPE :KIND X) might be
296   ;;   * :PRIMITIVE, which is handled by the FIND-CLASS case.
297   ;;   * :DEFINED, which is handled specially.
298   ;;   * :INSTANCE, which is handled by the FIND-CLASS case.
299   ;;   * :FORTHCOMING-DEFCLASS-TYPE, which is an internal-to-the-compiler
300   ;;     note that we don't try to report.
301   ;;   * NIL, in which case there's nothing to see here, move along.
302   (when (eq (info :type :kind x) :defined)
303     (format s "~@:_It names a type specifier."))
304   (let ((symbol-named-class (cl:find-class x nil)))
305     (when symbol-named-class
306       (format s "~@:_It names a class ~A." symbol-named-class)
307       (describe symbol-named-class s))))