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