1 ;;;; most of the DESCRIBE mechanism -- that part which isn't derived
4 ;;;; This software is part of the SBCL system. See the README file for
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.
13 (in-package "SB-IMPL")
15 (defvar *describe-indentation-step* 3
17 "the number of spaces that sets off each line of a recursive description")
19 (declaim (ftype (function (t stream)) describe-object))
20 (defgeneric describe-object ((x t) stream))
22 (defun describe (x &optional (stream-designator *standard-output*))
24 "Print a description of the object X."
25 (let ((stream (out-synonym-of stream-designator)))
26 #+nil (fresh-line stream)
27 (pprint-logical-block (stream nil)
28 (describe-object x stream)))
31 ;;;; miscellaneous DESCRIBE-OBJECT methods
33 (defmethod describe-object ((x t) s)
34 (format s "~@<~S ~_is a ~S.~:>" x (type-of x)))
36 (defmethod describe-object ((x cons) s)
38 (when (and (legal-function-name-p x)
40 (format s "Its FDEFINITION is ~S.~@:_" (fdefinition x))
41 ;; TO DO: should check for SETF documentation.
42 ;; TO DO: should make it clear whether the definition is a
43 ;; DEFUN (SETF FOO) or DEFSETF FOO or what.
46 (defmethod describe-object ((x array) s)
47 (let ((rank (array-rank x)))
49 (format s "~S ~_is " x)
50 (write-string (if (%array-displaced-p x) "a displaced" "an") s)
51 (format s " array of rank ~S." rank)
52 (format s "~@:_Its dimensions are ~S." (array-dimensions x)))
55 "~@:_~S is a ~:[~;displaced ~]vector of length ~S." x
56 (and (array-header-p x) (%array-displaced-p x)) (length x))
57 (when (array-has-fill-pointer-p x)
58 (format s "~@:_It has a fill pointer, currently ~S."
60 (let ((array-element-type (array-element-type x)))
61 (unless (eq array-element-type t)
63 "~@:_Its element type is specialized to ~S."
64 array-element-type))))
66 (defmethod describe-object ((x hash-table) s)
67 (declare (type stream s))
68 (format s "~@<~S ~_is an ~S hash table.~:>" x (hash-table-test x))
69 (format s "~_Its SIZE is ~S." (hash-table-size x))
71 "~@:_~@<Its REHASH-SIZE is ~S. ~_Its REHASH-THRESHOLD is ~S.~:>"
72 (hash-table-rehash-size x)
73 (hash-table-rehash-threshold x))
74 (let ((count (hash-table-count x)))
75 (format s "~@:_It holds ~S key/value pair~:P~:[: ~2I~_~;.~]"
78 (declare (type index n))
81 (write-char #\space s))
83 (when (and *print-length* (> n *print-length*))
86 (format s "~:_(~S ~S)" k v)))))
88 (defmethod describe-object ((condition condition) s)
89 (sb-conditions::describe-condition condition s))
91 ;;;; DESCRIBE-OBJECT methods for symbols and functions, including all
92 ;;;; sorts of messy stuff about documentation, type information,
93 ;;;; packaging, function implementation, etc..
95 ;;; Print the specified kind of documentation about the given NAME. If
96 ;;; NAME is null, or not a valid name, then don't print anything.
97 (declaim (ftype (function (symbol stream t t) (values)) %describe-doc))
98 (defun %describe-doc (name s kind kind-doc)
99 (when (and name (typep name '(or symbol cons)))
100 (let ((doc (fdocumentation name kind)))
102 (format s "~_~@(~A documentation:~)~@:_ ~A"
103 (or kind-doc kind) doc))))
106 ;;; Describe various stuff about the functional semantics attached to
107 ;;; the specified Name. Type-Spec is the function type specifier
108 ;;; extracted from the definition, or NIL if none.
109 (declaim (ftype (function ((or symbol cons) stream t)) %describe-function-name))
110 (defun %describe-function-name (name s type-spec)
111 (multiple-value-bind (type where)
112 (if (or (symbolp name) (and (listp name) (eq (car name) 'setf)))
113 (values (type-specifier (info :function :type name))
114 (info :function :where-from name))
115 (values type-spec :defined))
117 (format s "~@:_Its ~(~A~) argument types are:~@:_ ~S"
119 (format s "~@:_Its result type is:~@:_ ~S" (third type))))
120 (let ((inlinep (info :function :inlinep name)))
122 (format s "~@:_It is currently declared ~(~A~);~
123 ~:[no~;~] expansion is available."
124 inlinep (info :function :inline-expansion name)))))
126 ;;; Interpreted function describing; handles both closure and
127 ;;; non-closure functions. Instead of printing the compiled-from info,
128 ;;; we print the definition.
129 (defun %describe-function-interpreted (x s kind name)
130 (declare (type stream s))
131 (multiple-value-bind (exp closure-p dname)
132 (sb-eval:interpreted-function-lambda-expression x)
133 (let ((args (sb-eval:interpreted-function-arglist x)))
134 (format s "~@:_~@(~@[~A ~]arguments:~@:_~)" kind)
136 (format s " ~<~S~:>" args)
137 (write-string " There are no arguments." s)))
138 (let ((name (or name dname)))
139 (%describe-doc name s 'function kind)
140 (unless (eq kind :macro)
141 (%describe-function-name
144 (type-specifier (sb-eval:interpreted-function-type x)))))
146 (format s "~@:_Its closure environment is:")
147 (pprint-logical-block (s nil)
148 (pprint-indent :current 2)
149 (let ((clos (sb-eval:interpreted-function-closure x)))
150 (dotimes (i (length clos))
151 (format s "~@:_~S: ~S" i (svref clos i))))))
152 (format s "~@:_Its definition is:~@:_ ~S" exp)))
154 ;;; Print information from the debug-info about where CODE-OBJ was
156 (defun %describe-compiled-from (code-obj s)
157 (declare (type stream s))
158 (let ((info (sb-kernel:%code-debug-info code-obj)))
160 (let ((sources (sb-c::debug-info-source info)))
161 (format s "~@:_On ~A it was compiled from:"
162 ;; FIXME: The FORMAT-UNIVERSAL-TIME calls in the system
163 ;; should become more consistent, probably not using
164 ;; any nondefault options.
165 (format-universal-time nil
166 (sb-c::debug-source-compiled
168 :style :abbreviated))
169 (dolist (source sources)
170 (let ((name (sb-c::debug-source-name source)))
171 (ecase (sb-c::debug-source-from source)
173 (format s "~@:_~A~@:_ Created: " (namestring name))
174 (sb-int:format-universal-time t (sb-c::debug-source-created
176 (let ((comment (sb-c::debug-source-comment source)))
178 (format s "~@:_ Comment: ~A" comment))))
179 (:lisp (format s "~@:_~S" name)))))))))
181 ;;; Describe a compiled function. The closure case calls us to print
183 (defun %describe-function-compiled (x s kind name)
184 (declare (type stream s))
185 ;; FIXME: The lowercaseness of %FUNCTION-ARGLIST results, and the
186 ;; non-sentenceness of the "Arguments" label, makes awkward output.
187 ;; Better would be "Its arguments are: ~S" (with uppercase argument
188 ;; names) when arguments are known, and otherwise "There is no
189 ;; information available about its arguments." or "It has no
190 ;; arguments." (And why is %FUNCTION-ARGLIST a string instead of a
191 ;; list of symbols anyway?)
192 (let ((args (%function-arglist x)))
193 (format s "~@:_~@(~@[~A ~]arguments:~@:_~)" kind)
195 (format s " There is no argument information available."))
197 (write-string " There are no arguments." s))
200 (pprint-logical-block (s nil)
201 (pprint-indent :current 2)
202 (write-string args s)))))
203 (let ((name (or name (%function-name x))))
204 (%describe-doc name s 'function kind)
205 (unless (eq kind :macro)
206 (%describe-function-name name s (%function-type x))))
207 (%describe-compiled-from (sb-kernel:function-code-header x) s))
209 (defun %describe-function-byte-compiled (x s kind name)
210 (declare (type stream s))
211 (let ((name (or name (sb-c::byte-function-name x))))
212 (%describe-doc name s 'function kind)
213 (unless (eq kind :macro)
214 (%describe-function-name name s 'function)))
215 (%describe-compiled-from (sb-c::byte-function-component x) s))
217 ;;; Describe a function with the specified kind and name. The latter
218 ;;; arguments provide some information about where the function came
219 ;;; from. Kind NIL means not from a name.
220 (defun %describe-function (x s &optional (kind nil) name)
221 (declare (type function x))
222 (declare (type stream s))
223 (declare (type (member :macro :function nil) kind))
226 (:macro (format s "Macro-function: ~S" x))
227 (:function (format s "Function: ~S" x))
228 ((nil) (format s "~S is a function." x)))
230 (#.sb-vm:closure-header-type
231 (%describe-function-compiled (%closure-function x) s kind name)
232 (format s "~@:_Its closure environment is:")
233 (pprint-logical-block (s nil)
234 (pprint-indent :current 8)
235 (dotimes (i (- (get-closure-length x) (1- sb-vm:closure-info-offset)))
236 (format s "~@:_~S: ~S" i (%closure-index-ref x i)))))
237 ((#.sb-vm:function-header-type #.sb-vm:closure-function-header-type)
238 (%describe-function-compiled x s kind name))
239 (#.sb-vm:funcallable-instance-header-type
241 (sb-kernel:byte-function
242 (%describe-function-byte-compiled x s kind name))
243 (sb-kernel:byte-closure
244 (%describe-function-byte-compiled (byte-closure-function x)
246 (format s "~@:_Its closure environment is:")
247 (pprint-logical-block (s nil)
248 (pprint-indent :current 8)
249 (let ((data (byte-closure-data x)))
250 (dotimes (i (length data))
251 (format s "~@:_~S: ~S" i (svref data i))))))
252 (sb-eval:interpreted-function
253 (%describe-function-interpreted x s kind name))
254 (standard-generic-function
255 ;; There should be a special method for this case; we'll
257 (describe-object x s))
259 (format s "~@:_It is an unknown type of funcallable instance."))))
261 (format s "~@:_It is an unknown type of function."))))
263 (defmethod describe-object ((x function) s)
264 (%describe-function x s))
266 (defmethod describe-object ((x symbol) s)
267 (declare (type stream s))
269 ;; Describe the packaging.
270 (let ((package (symbol-package x)))
272 (multiple-value-bind (symbol status)
273 (find-symbol (symbol-name x) package)
274 (declare (ignore symbol))
275 (format s "~S is an ~(~A~) symbol in ~S."
276 x status (symbol-package x)))
277 (format s "~S is an uninterned symbol." x)))
278 ;; TO DO: We could grovel over all packages looking for and
279 ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
280 ;; availability in some package even after (SYMBOL-PACKAGE X) has
283 ;; Describe the value cell.
284 (let* ((kind (info :variable :kind x))
286 (:special "special variable")
287 (:constant "constant")
288 (:global "undefined variable")
292 (let ((info (info :variable :alien-info x)))
293 (format s "~@:_~@<It is an alien at #X~8,'0X of type ~3I~:_~S.~:>~@:_"
294 (sap-int (eval (sb-alien::heap-alien-info-sap-form info)))
295 (sb-alien-internals:unparse-alien-type
296 (sb-alien::heap-alien-info-type info)))
297 (format s "~@<Its current value is ~3I~:_~S.~:>"
300 (format s "~@:_It is a ~A; its value is ~S." wot (symbol-value x)))
301 ((not (eq kind :global))
302 (format s "~@:_It is a ~A; no current value." wot)))
304 (when (eq (info :variable :where-from x) :declared)
305 (format s "~@:_Its declared type is ~S."
306 (type-specifier (info :variable :type x))))
308 (%describe-doc x s 'variable kind))
310 ;; Print out properties.
311 (format s "~@[~@:_Its SYMBOL-PLIST is ~@<~2I~_~S~:>.~]" (symbol-plist x))
313 ;; Describe the function cell.
314 (cond ((macro-function x)
315 (%describe-function (macro-function x) s :macro x))
316 ((special-operator-p x)
317 (%describe-doc x s 'function "Special form"))
319 (%describe-function (fdefinition x) s :function x)))
321 ;; TO DO: Print out other stuff from the INFO database:
322 ;; * Does it name a type or class?
323 ;; * Is it a structure accessor? (important since those are
324 ;; magical in some ways, e.g. blasting the structure if you
327 ;; Print other documentation.
328 (%describe-doc x s 'structure "Structure")
329 (%describe-doc x s 'type "Type")
330 (%describe-doc x s 'setf "Setf macro")
331 (dolist (assoc (info :random-documentation :stuff x))
333 "~@:_Documentation on the ~(~A~):~@:_~A"