0.pre7.54:
[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 (defvar *describe-indentation-step* 3
16   #+sb-doc
17   "the number of spaces that sets off each line of a recursive description")
18
19 (declaim (ftype (function (t stream)) describe-object))
20 (defgeneric describe-object ((x t) stream))
21
22 (defun describe (x &optional (stream-designator *standard-output*))
23   #+sb-doc
24   "Print a description of the object X."
25   (let ((stream (out-synonym-of stream-designator)))
26     (pprint-logical-block (stream nil)
27       (fresh-line stream)
28       (describe-object x stream)
29       (fresh-line stream)))
30   (values))
31 \f
32 ;;;; miscellaneous DESCRIBE-OBJECT methods
33
34 (defmethod describe-object ((x t) s)
35   (format s "~@<~S ~_is a ~S.~:>" x (type-of x)))
36
37 (defmethod describe-object ((x cons) s)
38   (call-next-method)
39   (when (and (legal-function-name-p x)
40              (fboundp x))
41     (%describe-function (fdefinition x) s :function x)
42     ;;was: (format s "~@:_Its FDEFINITION is ~S.~@:_" (fdefinition x))
43     ;; TO DO: should check for SETF documentation.
44     ;; TO DO: should make it clear whether the definition is a
45     ;; DEFUN (SETF FOO) or DEFSETF FOO or what.
46     ))
47
48 (defmethod describe-object ((x array) s)
49   (let ((rank (array-rank x)))
50     (cond ((> rank 1)
51            (format s "~S ~_is " x)
52            (write-string (if (%array-displaced-p x) "a displaced" "an") s)
53            (format s " array of rank ~S." rank)
54            (format s "~@:_Its dimensions are ~S." (array-dimensions x)))
55           (t
56            (format s
57                    "~@:_~S is a ~:[~;displaced ~]vector of length ~S." x
58                    (and (array-header-p x) (%array-displaced-p x)) (length x))
59            (when (array-has-fill-pointer-p x)
60              (format s "~@:_It has a fill pointer, currently ~S."
61                      (fill-pointer x))))))
62   (let ((array-element-type (array-element-type x)))
63     (unless (eq array-element-type t)
64       (format s
65               "~@:_Its element type is specialized to ~S."
66               array-element-type))))
67
68 (defmethod describe-object ((x hash-table) s)
69   (declare (type stream s))
70   (format s "~@<~S ~_is an ~S hash table.~:>" x (hash-table-test x))
71   (format s "~_Its SIZE is ~S." (hash-table-size x))
72   (format s
73           "~@:_~@<Its REHASH-SIZE is ~S. ~_Its REHASH-THRESHOLD is ~S.~:>"
74           (hash-table-rehash-size x)
75           (hash-table-rehash-threshold x))
76   (let ((count (hash-table-count x)))
77     (format s "~@:_It holds ~S key/value pair~:P~:[: ~2I~_~;.~]"
78             count (zerop count))
79     (let ((n 0))
80       (declare (type index n))
81       (dohash (k v x)
82         (unless (zerop n)
83           (write-char #\space s))
84         (incf n)
85         (when (and *print-length* (> n *print-length*))
86           (format s "~:_...")
87           (return))
88         (format s "~:_(~@<~S ~:_~S~:>)" k v)))))
89
90 (defmethod describe-object ((condition condition) s)
91   (sb-kernel:describe-condition condition s))
92 \f
93 ;;;; DESCRIBE-OBJECT methods for symbols and functions, including all
94 ;;;; sorts of messy stuff about documentation, type information,
95 ;;;; packaging, function implementation, etc..
96
97 ;;; Print the specified kind of documentation about the given NAME. If
98 ;;; NAME is null, or not a valid name, then don't print anything.
99 (declaim (ftype (function (t stream t t) (values)) %describe-doc))
100 (defun %describe-doc (name s kind kind-doc)
101   (when (and name (typep name '(or symbol cons)))
102     (let ((doc (fdocumentation name kind)))
103       (when doc
104         (format s "~_~@(~A documentation:~)~@:_  ~A"
105                 (or kind-doc kind) doc))))
106   (values))
107
108 ;;; Describe various stuff about the functional semantics attached to
109 ;;; the specified NAME, if NAME is the kind of thing you can look
110 ;;; up as a name. (In the case of anonymous closures and other
111 ;;; things, it might not be.) TYPE-SPEC is the function type specifier
112 ;;; extracted from the definition, or NIL if none.
113 (declaim (ftype (function (t stream t)) %describe-function-name))
114 (defun %describe-function-name (name s type-spec) 
115   (when (and name (typep name '(or symbol cons)))
116     (multiple-value-bind (type where)
117         (if (or (symbolp name) (and (listp name) (eq (car name) 'setf)))
118             (values (type-specifier (info :function :type name))
119                     (info :function :where-from name))
120             (values type-spec :defined))
121       (when (consp type)
122         (format s "~@:_Its ~(~A~) argument types are:~@:_  ~S"
123                 where (second type))
124         (format s "~@:_Its result type is:~@:_  ~S" (third type))))
125     (let ((inlinep (info :function :inlinep name)))
126       (when inlinep
127         (format s
128                 "~@:_It is currently declared ~(~A~);~
129                  ~:[no~;~] expansion is available."
130                 inlinep (info :function :inline-expansion name))))))
131
132 ;;; Print information from the debug-info about where CODE-OBJ was
133 ;;; compiled from.
134 (defun %describe-compiled-from (code-obj s)
135   (declare (type stream s))
136   (let ((info (sb-kernel:%code-debug-info code-obj)))
137     (when info
138       (let ((sources (sb-c::debug-info-source info)))
139         (when sources
140           (format s "~@:_On ~A it was compiled from:"
141                   ;; FIXME: The FORMAT-UNIVERSAL-TIME calls in the system
142                   ;; should become more consistent, probably not using
143                   ;; any nondefault options.
144                   (format-universal-time nil
145                                          (sb-c::debug-source-compiled
146                                           (first sources))
147                                          :style :abbreviated))
148           (dolist (source sources)
149             (let ((name (sb-c::debug-source-name source)))
150               (ecase (sb-c::debug-source-from source)
151                 (:file
152                  (format s "~@:_~A~@:_  Created: " (namestring name))
153                  (format-universal-time s (sb-c::debug-source-created
154                                            source)))
155                 (:lisp (format s "~@:_~S" name))))))))))
156
157 ;;; Describe a compiled function. The closure case calls us to print
158 ;;; the guts.
159 (defun %describe-function-compiled (x s kind name)
160   (declare (type stream s))
161   ;; FIXME: The lowercaseness of %FUNCTION-ARGLIST results, and the
162   ;; non-sentenceness of the "Arguments" label, makes awkward output.
163   ;; Better would be "Its arguments are: ~S" (with uppercase argument
164   ;; names) when arguments are known, and otherwise "There is no
165   ;; information available about its arguments." or "It has no
166   ;; arguments." (And why is %FUNCTION-ARGLIST a string instead of a
167   ;; list of symbols anyway?)
168   (let ((args (%function-arglist x)))
169     (format s "~@:_~@(~@[~A ~]arguments:~@:_~)" kind)
170     (cond ((not args)
171            (format s "  There is no argument information available."))
172           ((string= args "()")
173            (write-string "  There are no arguments." s))
174           (t
175            (write-string "  " s)
176            (pprint-logical-block (s nil)
177              (pprint-indent :current 2)
178              (write-string args s)))))
179   (let ((name (or name (%function-name x))))
180     (%describe-doc name s 'function kind)
181     (unless (eq kind :macro)
182       (%describe-function-name name s (%fun-type x))))
183   (%describe-compiled-from (sb-kernel:function-code-header x) s))
184
185 ;;; Describe a function with the specified kind and name. The latter
186 ;;; arguments provide some information about where the function came
187 ;;; from. KIND=NIL means not from a name.
188 (defun %describe-function (x s &optional (kind nil) name)
189   (declare (type function x))
190   (declare (type stream s))
191   (declare (type (member :macro :function nil) kind))
192   (fresh-line s)
193   (ecase kind
194     (:macro (format s "Macro-function: ~S" x))
195     (:function (format s "Function: ~S" x))
196     ((nil) (format s "~S is a function." x)))
197   (case (get-type x)
198     (#.sb-vm:closure-header-type
199      (%describe-function-compiled (%closure-function x) s kind name)
200      (format s "~@:_Its closure environment is:")
201      (pprint-logical-block (s nil)
202        (pprint-indent :current 8)
203        (dotimes (i (- (get-closure-length x) (1- sb-vm:closure-info-offset)))
204          (format s "~@:_~S: ~S" i (%closure-index-ref x i)))))
205     ((#.sb-vm:function-header-type #.sb-vm:closure-function-header-type)
206      (%describe-function-compiled x s kind name))
207     (#.sb-vm:funcallable-instance-header-type
208      (typecase x
209        (standard-generic-function
210         ;; There should be a special method for this case; we'll
211         ;; delegate to that.
212         (describe-object x s))
213        (t
214         (format s "~@:_It is an unknown type of funcallable instance."))))
215     (t
216      (format s "~@:_It is an unknown type of function."))))
217
218 (defmethod describe-object ((x function) s)
219   (%describe-function x s))
220   
221 (defmethod describe-object ((x symbol) s)
222   (declare (type stream s))
223
224   ;; Describe the packaging.
225   (let ((package (symbol-package x)))
226     (if package
227         (multiple-value-bind (symbol status)
228             (find-symbol (symbol-name x) package)
229           (declare (ignore symbol))
230           (format s "~S is ~_an ~(~A~) symbol ~_in ~S."
231                   x status (symbol-package x)))
232         (format s "~S is ~_an uninterned symbol." x)))
233   ;; TO DO: We could grovel over all packages looking for and
234   ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
235   ;; availability in some package even after (SYMBOL-PACKAGE X) has
236   ;; been set to NIL.
237
238   ;; Describe the value cell.
239   (let* ((kind (info :variable :kind x))
240          (wot (ecase kind
241                 (:special "special variable")
242                 (:constant "constant")
243                 (:global "undefined variable")
244                 (:alien nil))))
245     (cond
246      ((eq kind :alien)
247       (let ((info (info :variable :alien-info x)))
248         (format s "~@:_~@<It is an alien at #X~8,'0X of type ~3I~:_~S.~:>~@:_"
249                 (sap-int (eval (sb-alien::heap-alien-info-sap-form info)))
250                 (sb-alien-internals:unparse-alien-type
251                  (sb-alien::heap-alien-info-type info)))
252         (format s "~@<Its current value is ~3I~:_~S.~:>"
253                 (eval x))))
254      ((boundp x)
255       (format s "~@:_It is a ~A; its ~_value is ~S." wot (symbol-value x)))
256      ((not (eq kind :global))
257       (format s "~@:_It is a ~A; no current value." wot)))
258
259     (when (eq (info :variable :where-from x) :declared)
260       (format s "~@:_Its declared type ~_is ~S."
261               (type-specifier (info :variable :type x))))
262
263     (%describe-doc x s 'variable kind))
264
265   ;; Print out properties.
266   (format s "~@[~@:_Its SYMBOL-PLIST is ~@<~2I~_~S~:>.~]" (symbol-plist x))
267
268   ;; Describe the function cell.
269   (cond ((macro-function x)
270          (%describe-function (macro-function x) s :macro x))
271         ((special-operator-p x)
272          (%describe-doc x s 'function "Special form"))
273         ((fboundp x)
274          (%describe-function (fdefinition x) s :function x)))
275
276   ;; FIXME: Print out other stuff from the INFO database:
277   ;;   * Does it name a type?
278   ;;   * Is it a structure accessor? (This is important since those are 
279   ;;     magical in some ways, e.g. blasting the structure if you 
280   ;;     redefine them.)
281
282   ;; Print other documentation.
283   (%describe-doc x s 'structure "Structure")
284   (%describe-doc x s 'type "Type")
285   (%describe-doc x s 'setf "Setf macro")
286
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   ;; Describe the associated class, if any.
294   (let ((symbol-named-class (cl:find-class x nil)))
295     (when symbol-named-class
296       (format t "~&It names a class ~A." symbol-named-class)
297       (describe symbol-named-class))))