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") ;(SB-IMPL, not SB!IMPL, since we're built in warm load.)
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 (pprint-logical-block (stream nil)
28 (describe-object x stream)
32 ;;;; miscellaneous DESCRIBE-OBJECT methods
34 (defmethod describe-object ((x t) s)
35 (format s "~@<~S ~_is a ~S.~:>" x (type-of x)))
37 (defmethod describe-object ((x cons) s)
39 (when (and (legal-fun-name-p x)
41 (%describe-fun (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.
48 (defmethod describe-object ((x array) s)
49 (let ((rank (array-rank x)))
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)))
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."
62 (let ((array-element-type (array-element-type x)))
63 (unless (eq array-element-type t)
65 "~@:_Its element type is specialized to ~S."
66 array-element-type))))
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))
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~_~;.~]"
80 (declare (type index n))
83 (write-char #\space s))
85 (when (and *print-length* (> n *print-length*))
88 (format s "~:_(~@<~S ~:_~S~:>)" k v)))))
90 (defmethod describe-object ((condition condition) s)
91 (sb-kernel:describe-condition condition s))
93 ;;;; DESCRIBE-OBJECT methods for symbols and functions, including all
94 ;;;; sorts of messy stuff about documentation, type information,
95 ;;;; packaging, function implementation, etc..
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)))
104 (format s "~_~@(~A documentation:~)~@:_ ~A"
105 (or kind-doc kind) doc))))
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-fun-name))
114 (defun %describe-fun-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))
122 (format s "~@:_Its ~(~A~) argument types are:~@:_ ~S"
124 (format s "~@:_Its result type is:~@:_ ~S" (third type))))
125 (let ((inlinep (info :function :inlinep name)))
128 "~@:_It is currently declared ~(~A~);~
129 ~:[no~;~] expansion is available."
130 inlinep (info :function :inline-expansion-designator name))))))
132 ;;; Print information from the debug-info about where CODE-OBJ was
134 (defun %describe-compiled-from (code-obj s)
135 (declare (type stream s))
136 (let ((info (sb-kernel:%code-debug-info code-obj)))
138 (let ((sources (sb-c::debug-info-source info)))
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
147 :style :abbreviated))
148 (dolist (source sources)
149 (let ((name (sb-c::debug-source-name source)))
150 (ecase (sb-c::debug-source-from source)
152 (format s "~@:_~A~@:_ Created: " (namestring name))
153 (format-universal-time s (sb-c::debug-source-created
155 (:lisp (format s "~@:_~S" name))))))))))
157 ;;; Describe a compiled function. The closure case calls us to print
159 (defun %describe-fun-compiled (x s kind name)
160 (declare (type stream s))
161 (let ((args (%simple-fun-arglist x)))
163 (write-string " There are no arguments." s))
165 (format s "~@:_~@(The ~@[~A's ~]arguments are:~@:_~)" kind)
167 (let ((*print-pretty* t)
171 (pprint-logical-block (s nil)
172 (pprint-indent :current 2)
173 (format s "~A" args))))))
174 (let ((name (or name (%simple-fun-name x))))
175 (%describe-doc name s 'function kind)
176 (unless (eq kind :macro)
177 (%describe-fun-name name s (%simple-fun-type x))))
178 (%describe-compiled-from (sb-kernel:fun-code-header x) s))
180 ;;; Describe a function object. KIND and NAME provide some information
181 ;;; about where the function came from.
182 (defun %describe-fun (x s &optional (kind :function) (name nil))
183 (declare (type function x))
184 (declare (type stream s))
185 (declare (type (member :macro :function) kind))
188 (:macro (format s "Macro-function: ~S" x))
190 (format s "Function: ~S" x)
191 (format s "~S is a function." x))))
192 (format s "~@:_Its associated name (as in ~S) is ~S."
193 'function-lambda-expression
196 (#.sb-vm:closure-header-widetag
197 (%describe-fun-compiled (%closure-fun x) s kind name)
198 (format s "~@:_Its closure environment is:")
199 (pprint-logical-block (s nil)
200 (pprint-indent :current 8)
201 (dotimes (i (- (get-closure-length x) (1- sb-vm:closure-info-offset)))
202 (format s "~@:_~S: ~S" i (%closure-index-ref x i)))))
203 ((#.sb-vm:simple-fun-header-widetag #.sb-vm:closure-fun-header-widetag)
204 (%describe-fun-compiled x s kind name))
205 (#.sb-vm:funcallable-instance-header-widetag
206 ;; Only STANDARD-GENERIC-FUNCTION would be handled here, but
207 ;; since it has its own DESCRIBE-OBJECT method, it should've been
208 ;; picked off before getting here. So hopefully we never get here.
209 (format s "~@:_It is an unknown type of funcallable instance."))
211 (format s "~@:_It is an unknown type of function."))))
213 (defmethod describe-object ((x function) s)
214 (%describe-fun x s :function))
216 (defgeneric describe-symbol-fdefinition (function stream &key (name nil) ))
218 (defmethod describe-symbol-fdefinition ((fun function) stream &key name)
219 (%describe-fun fun stream :function name))
221 (defmethod describe-symbol-fdefinition ((fun standard-generic-function) stream
223 (declare (ignore name))
225 (describe-object fun stream))
227 (defmethod describe-object ((x symbol) s)
228 (declare (type stream s))
230 ;; Describe the packaging.
231 (let ((package (symbol-package x)))
233 (multiple-value-bind (symbol status)
234 (find-symbol (symbol-name x) package)
235 (declare (ignore symbol))
236 (format s "~S is ~_an ~(~A~) symbol ~_in ~S."
237 x status (symbol-package x)))
238 (format s "~S is ~_an uninterned symbol." x)))
239 ;; TO DO: We could grovel over all packages looking for and
240 ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
241 ;; availability in some package even after (SYMBOL-PACKAGE X) has
244 ;; Describe the value cell.
245 (let* ((kind (info :variable :kind x))
247 (:special "special variable")
248 (:constant "constant")
249 (:global "undefined variable")
253 (let ((info (info :variable :alien-info x)))
254 (format s "~@:_~@<It is an alien at #X~8,'0X of type ~3I~:_~S.~:>~@:_"
255 (sap-int (eval (sb-alien::heap-alien-info-sap-form info)))
256 (sb-alien-internals:unparse-alien-type
257 (sb-alien::heap-alien-info-type info)))
258 (format s "~@<Its current value is ~3I~:_~S.~:>"
261 (format s "~@:_It is a ~A; its ~_value is ~S." wot (symbol-value x)))
262 ((not (eq kind :global))
263 (format s "~@:_It is a ~A; no current value." wot)))
265 (when (eq (info :variable :where-from x) :declared)
266 (format s "~@:_Its declared type ~_is ~S."
267 (type-specifier (info :variable :type x))))
269 (%describe-doc x s 'variable kind))
271 ;; Print out properties.
272 (format s "~@[~@:_Its SYMBOL-PLIST is ~@<~2I~_~S~:>.~]" (symbol-plist x))
274 ;; Describe the function cell.
275 (cond ((macro-function x)
276 (%describe-fun (macro-function x) s :macro x))
277 ((special-operator-p x)
278 (%describe-doc x s :function "Special form"))
280 (describe-symbol-fdefinition (fdefinition x) s :name x)))
282 ;; FIXME: Print out other stuff from the INFO database:
283 ;; * Does it name a type?
284 ;; * Is it a structure accessor? (This is important since those are
285 ;; magical in some ways, e.g. blasting the structure if you
288 ;; Print other documentation.
289 (%describe-doc x s 'structure "Structure")
290 (%describe-doc x s 'type "Type")
291 (%describe-doc x s 'setf "Setf macro")
293 (dolist (assoc (info :random-documentation :stuff x))
295 "~@:_Documentation on the ~(~A~):~@:_~A"
299 ;; Describe the associated class, if any.
300 (let ((symbol-named-class (cl:find-class x nil)))
301 (when symbol-named-class
302 (format s "~&It names a class ~A." symbol-named-class)
303 (describe symbol-named-class))))