1 ;;;; the DESCRIBE system
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 ;;; SB-IMPL, not SB!IMPL, since we're built in warm load.
13 (in-package "SB-IMPL")
15 ;;;; Utils, move elsewhere.
17 (defun class-name-or-class (class)
18 (let ((name (class-name class
)))
19 (if (eq class
(find-class name nil
))
24 (if (typep x
'standard-generic-function
)
25 (sb-pcl:generic-function-name x
)
28 ;;;; the ANSI interface to function names (and to other stuff too)
29 ;;; Note: this function gets called by the compiler (as of 1.0.17.x,
30 ;;; in MAYBE-INLINE-SYNTACTIC-CLOSURE), and so although ANSI says
31 ;;; we're allowed to return NIL here freely, it seems plausible that
32 ;;; small changes to the circumstances under which this function
33 ;;; returns non-NIL might have subtle consequences on the compiler.
34 ;;; So it might be desirable to have the compiler not rely on this
35 ;;; function, eventually.
36 (defun function-lambda-expression (fun)
38 "Return (VALUES DEFINING-LAMBDA-EXPRESSION CLOSURE-P NAME), where
39 DEFINING-LAMBDA-EXPRESSION is NIL if unknown, or a suitable argument
40 to COMPILE otherwise, CLOSURE-P is non-NIL if the function's definition
41 might have been enclosed in some non-null lexical environment, and
42 NAME is some name (for debugging only) or NIL if there is no name."
43 (declare (type function fun
))
46 (sb-eval:interpreted-function
47 (let ((name (sb-eval:interpreted-function-name fun
))
48 (lambda-list (sb-eval:interpreted-function-lambda-list fun
))
49 (declarations (sb-eval:interpreted-function-declarations fun
))
50 (body (sb-eval:interpreted-function-body fun
)))
51 (values `(lambda ,lambda-list
52 ,@(when declarations
`((declare ,@declarations
)))
56 (let* ((name (fun-name fun
))
57 (fun (%simple-fun-self
(%fun-fun fun
)))
58 (code (sb-di::fun-code-header fun
))
59 (info (sb-kernel:%code-debug-info code
))
60 (source (if info
(sb-c::debug-info-source info
))))
61 (cond ((and source
(sb-c::debug-source-form source
)
62 (eq (sb-c::debug-source-function source
) fun
))
63 (values (sb-c::debug-source-form source
) nil name
))
64 ((legal-fun-name-p name
)
65 (let ((exp (fun-name-inline-expansion name
)))
66 (values exp
(not exp
) name
)))
68 (values nil t name
)))))))
70 ;;; Prints X on a single line, limiting output length by *PRINT-RIGHT-MARGIN*
71 ;;; -- good for printing object parts, etc.
72 (defun prin1-to-line (x &key
(columns 1) (reserve 0))
73 (let* ((line (write-to-string x
:escape t
:readably nil
:lines
2 :circle t
))
74 (p (position #\newline line
))
75 (limit (truncate (- *print-right-margin
* reserve
) columns
)))
76 (flet ((trunc (&optional end
)
77 (let ((line-end (- limit
2)))
78 (with-output-to-string (s)
79 (write-string line s
:end
(if end
82 (write-string ".." s
)))))
85 ((> (length line
) limit
)
90 (defun describe (object &optional
(stream-designator *standard-output
*))
92 "Print a description of OBJECT to STREAM-DESIGNATOR."
93 (let ((stream (out-synonym-of stream-designator
))
94 (*print-right-margin
* (or *print-right-margin
* 72))
96 (*suppress-print-errors
*
97 (if (subtypep 'serious-condition
*suppress-print-errors
*)
98 *suppress-print-errors
*
100 ;; Until sbcl-0.8.0.x, we did
101 ;; (FRESH-LINE STREAM)
102 ;; (PPRINT-LOGICAL-BLOCK (STREAM NIL)
104 ;; here. However, ANSI's specification of DEFUN DESCRIBE,
105 ;; DESCRIBE exists as an interface primarily to manage argument
106 ;; defaulting (including conversion of arguments T and NIL into
107 ;; stream objects) and to inhibit any return values from
109 ;; doesn't mention either FRESH-LINEing or PPRINT-LOGICAL-BLOCKing,
110 ;; and the example of typical DESCRIBE-OBJECT behavior in ANSI's
111 ;; specification of DESCRIBE-OBJECT will work poorly if we do them
112 ;; here. (The example method for DESCRIBE-OBJECT does its own
113 ;; FRESH-LINEing, which is a physical directive which works poorly
114 ;; inside a pretty-printer logical block.)
115 (handler-bind ((print-not-readable #'print-unreadably
))
116 (describe-object object stream
))
117 ;; We don't TERPRI here either (any more since sbcl-0.8.0.x), because
118 ;; again ANSI's specification of DESCRIBE doesn't mention it and
119 ;; ANSI's example of DESCRIBE-OBJECT does its own final TERPRI.
126 ;;;; * Each interesting class has a primary method of its own.
128 ;;;; * Output looks like
130 ;;;; object-self-string
131 ;;;; [object-type-string]
140 ;;;; * The newline policy that gets the whitespace right is for
141 ;;;; each block to both start and end with a newline.
143 (defgeneric object-self-string
(x))
145 (defmethod object-self-string (x)
148 (defmethod object-self-string ((x symbol
))
149 (let ((*package
* (find-package :keyword
)))
150 (prin1-to-string x
)))
152 (defgeneric object-type-string
(x))
154 (defmethod object-type-string (x)
155 (let ((type (class-name-or-class (class-of x
))))
157 (string-downcase type
)
158 (prin1-to-string type
))))
160 (defmethod object-type-string ((x cons
))
161 (if (listp (cdr x
)) "list" "cons"))
163 (defmethod object-type-string ((x hash-table
))
166 (defmethod object-type-string ((x condition
))
169 (defmethod object-type-string ((x structure-object
))
172 (defmethod object-type-string ((x standard-object
))
175 (defmethod object-type-string ((x function
))
177 (simple-fun "compiled function")
178 (closure "compiled closure")
180 (sb-eval:interpreted-function
181 "interpreted function")
185 "funcallable-instance")))
187 (defmethod object-type-string ((x stream
))
190 (defmethod object-type-string ((x sb-gray
:fundamental-stream
))
193 (defmethod object-type-string ((x package
))
196 (defmethod object-type-string ((x array
))
197 (cond ((or (stringp x
) (bit-vector-p x
))
198 (format nil
"~@[simple-~*~]~A"
199 (typep x
'simple-array
)
201 (base-string "base-string")
205 (if (simple-vector-p x
)
207 (format nil
"~@[simple ~*~]~@[specialized ~*~]~:[array~;vector~]"
208 (typep x
'simple-array
)
209 (neq t
(array-element-type x
))
212 (defmethod object-type-string ((x character
))
214 (standard-char "standard-char")
215 (base-char "base-char")
218 (defun print-standard-describe-header (x stream
)
219 (format stream
"~&~A~% [~A]~%"
220 (object-self-string x
)
221 (object-type-string x
)))
223 (defgeneric describe-object
(x stream
))
227 (defmethod describe-object ((x t
) s
)
228 (print-standard-describe-header x s
))
230 (defmethod describe-object ((x cons
) s
)
231 (print-standard-describe-header x s
)
232 (describe-function x nil s
))
234 (defmethod describe-object ((x function
) s
)
235 (print-standard-describe-header x s
)
236 (describe-function nil x s
))
238 (defmethod describe-object ((x class
) s
)
239 (print-standard-describe-header x s
)
240 (describe-class nil x s
)
241 (describe-instance x s
))
243 (defmethod describe-object ((x sb-pcl
::slot-object
) s
)
244 (print-standard-describe-header x s
)
245 (describe-instance x s
))
247 (defmethod describe-object ((x character
) s
)
248 (print-standard-describe-header x s
)
249 (format s
"~%Char-code: ~S" (char-code x
))
250 (format s
"~%Char-name: ~A" (char-name x
)))
252 (defmethod describe-object ((x array
) s
)
253 (print-standard-describe-header x s
)
254 (format s
"~%Element-type: ~S" (array-element-type x
))
256 (if (array-has-fill-pointer-p x
)
257 (format s
"~%Fill-pointer: ~S~%Size: ~S"
259 (array-total-size x
))
260 (format s
"~%Length: ~S" (length x
)))
261 (format s
"~%Dimensions: ~S" (array-dimensions x
)))
262 (let ((*print-array
* nil
))
263 (unless (typep x
'simple-array
)
264 (format s
"~%Adjustable: ~A" (if (adjustable-array-p x
) "yes" "no"))
265 (multiple-value-bind (to offset
) (array-displacement x
)
266 (if (format s
"~%Displaced-to: ~A~%Displaced-offset: ~S"
269 (format s
"~%Displaced: no"))))
270 (when (and (not (array-displacement x
)) (array-header-p x
))
271 (format s
"~%Storage vector: ~A"
272 (prin1-to-line (array-storage-vector x
))))
275 (defmethod describe-object ((x hash-table
) s
)
276 (print-standard-describe-header x s
)
277 ;; Don't print things which are already apparent from the printed
278 ;; representation -- COUNT, TEST, and WEAKNESS
279 (format s
"~%Occupancy: ~,1F" (float (/ (hash-table-count x
)
280 (hash-table-size x
))))
281 (format s
"~%Rehash-threshold: ~S" (hash-table-rehash-threshold x
))
282 (format s
"~%Rehash-size: ~S" (hash-table-rehash-size x
))
283 (format s
"~%Size: ~S" (hash-table-size x
))
284 (format s
"~%Synchronized: ~A" (if (hash-table-synchronized-p x
) "yes" "no"))
287 (defmethod describe-object ((symbol symbol
) stream
)
288 (print-standard-describe-header symbol stream
)
289 ;; Describe the value cell.
290 (let* ((kind (info :variable
:kind symbol
))
292 (:special
"a special variable")
293 (:macro
"a symbol macro")
294 (:constant
"a constant variable")
295 (:global
"a global variable")
296 (:unknown
"an undefined variable")
297 (:alien
"an alien variable"))))
298 (when (or (not (eq :unknown kind
)) (boundp symbol
))
299 (pprint-logical-block (stream nil
)
300 (format stream
"~@:_~A names ~A:" symbol wot
)
301 (pprint-indent :block
2 stream
)
302 (when (eq (info :variable
:where-from symbol
) :declared
)
303 (format stream
"~@:_Declared type: ~S"
304 (type-specifier (info :variable
:type symbol
))))
305 (when (info :variable
:always-bound symbol
)
306 (format stream
"~@:_Declared always-bound."))
309 (let ((info (info :variable
:alien-info symbol
)))
310 (format stream
"~@:_Value: ~S" (eval symbol
))
311 (format stream
"~@:_Type: ~S"
312 (sb-alien-internals:unparse-alien-type
313 (sb-alien::heap-alien-info-type info
)))
314 (format stream
"~@:_Address: #x~8,'0X"
315 (sap-int (sb-alien::heap-alien-info-sap info
)))))
317 (let ((expansion (info :variable
:macro-expansion symbol
)))
318 (format stream
"~@:_Expansion: ~S" expansion
)))
320 (format stream
"~:@_Value: ~S" (symbol-value symbol
)))
321 ((not (eq kind
:unknown
))
322 (format stream
"~:@_Currently unbound.")))
323 (describe-documentation symbol
'variable stream
)
326 ;; TODO: We could grovel over all packages looking for and
327 ;; reporting other phenomena, e.g. IMPORT and SHADOW, or
328 ;; availability in some package even after (SYMBOL-PACKAGE SYMBOL) has
331 ;; TODO: It might also be nice to describe (find-package symbol)
332 ;; if one exists. Maybe not all the exports, etc, but the package
334 (describe-function symbol nil stream
)
335 (describe-class symbol nil stream
)
338 (let* ((kind (info :type
:kind symbol
))
341 (or (info :type
:expander symbol
) t
))
343 (or (info :type
:translator symbol
) t
)))))
345 (pprint-newline :mandatory stream
)
346 (pprint-logical-block (stream nil
)
347 (format stream
"~@:_~A names a ~@[primitive~* ~]type-specifier:"
349 (eq kind
:primitive
))
350 (pprint-indent :block
2 stream
)
351 (describe-documentation symbol
'type stream
(eq t fun
))
353 (describe-lambda-list (if (eq :primitive kind
)
354 (%fun-lambda-list fun
)
355 (info :type
:lambda-list symbol
))
357 (multiple-value-bind (expansion ok
)
358 (handler-case (typexpand-1 symbol
)
359 (error () (values nil nil
)))
361 (format stream
"~@:_Expansion: ~S" expansion
)))))
364 (when (or (member symbol sb-c
::*policy-qualities
*)
365 (assoc symbol sb-c
::*policy-dependent-qualities
*))
366 (pprint-logical-block (stream nil
)
367 (pprint-newline :mandatory stream
)
368 (pprint-indent :block
2 stream
)
369 (format stream
"~A names a~:[ dependent~;n~] optimization policy quality:"
371 (member symbol sb-c
::*policy-qualities
*))
372 (describe-documentation symbol
'optimize stream t
))
375 ;; Print out properties.
376 (let ((plist (symbol-plist symbol
)))
378 (pprint-logical-block (stream nil
)
379 (format stream
"~%Symbol-plist:")
380 (pprint-indent :block
2 stream
)
381 (sb-pcl::doplist
(key value
) plist
382 (format stream
"~@:_~A -> ~A"
383 (prin1-to-line key
:columns
2 :reserve
5)
384 (prin1-to-line value
:columns
2 :reserve
5))))
387 (defmethod describe-object ((package package
) stream
)
388 (print-standard-describe-header package stream
)
389 (pprint-logical-block (stream nil
)
390 (describe-documentation package t stream
)
391 (flet ((humanize (list)
392 (sort (mapcar (lambda (x)
399 (describe-stuff label list stream
:escape nil
)))
401 (do-external-symbols (ext package
)
404 (let ((implemented (humanize (package-implemented-by-list package
)))
405 (implements (humanize (package-implements-list package
)))
406 (this (list (package-name package
))))
407 (when (package-locked-p package
)
408 (format stream
"~@:_Locked."))
409 (when (set-difference implemented this
:test
#'string
=)
410 (out "Implemented-by-list" implemented
))
411 (when (set-difference implements this
:test
#'string
=)
412 (out "Implements-list" implements
)))
413 (out "Nicknames" (humanize (package-nicknames package
)))
414 (out "Use-list" (humanize (package-use-list package
)))
415 (out "Used-by-list" (humanize (package-used-by-list package
)))
416 (out "Shadows" (humanize (package-shadowing-symbols package
)))
417 (out "Exports" (humanize exports
))
418 (format stream
"~@:_~S internal symbols."
419 (package-internal-symbol-count package
))))
422 ;;;; Helpers to deal with shared functionality
424 (defun describe-class (name class stream
)
425 (let* ((by-name (not class
))
426 (name (if class
(class-name class
) name
))
427 (class (if class class
(find-class name nil
))))
429 (let ((metaclass-name (class-name (class-of class
))))
430 (pprint-logical-block (stream nil
)
432 (format stream
"~@:_~A names the ~(~A~) ~S:"
436 (pprint-indent :block
2 stream
))
437 (describe-documentation class t stream
)
438 (when (sb-mop:class-finalized-p class
)
439 (describe-stuff "Class precedence-list"
440 (mapcar #'class-name-or-class
(sb-mop:class-precedence-list class
))
442 (describe-stuff "Direct superclasses"
443 (mapcar #'class-name-or-class
(sb-mop:class-direct-superclasses class
))
445 (let ((subs (mapcar #'class-name-or-class
(sb-mop:class-direct-subclasses class
))))
447 (describe-stuff "Direct subclasses" subs stream
)
448 (format stream
"~@:_No subclasses.")))
449 (unless (sb-mop:class-finalized-p class
)
450 (format stream
"~@:_Not yet finalized."))
451 (if (eq 'structure-class metaclass-name
)
452 (let* ((dd (find-defstruct-description name
))
453 (slots (dd-slots dd
)))
455 (format stream
"~@:_Slots:~:{~@:_ ~S~
456 ~@:_ Type: ~A ~@[~A~]~
458 (mapcar (lambda (dsd)
462 (unless (eq t
(dsd-raw-type dsd
))
466 (format stream
"~@:_No slots.")))
467 (let ((slots (sb-mop:class-direct-slots class
)))
469 (format stream
"~@:_Direct slots:~:{~@:_ ~S~
471 ~@[~@:_ Allocation: ~S~]~
472 ~@[~@:_ Initargs: ~{~S~^, ~}~]~
473 ~@[~@:_ Initform: ~S~]~
474 ~@[~@:_ Readers: ~{~S~^, ~}~]~
475 ~@[~@:_ Writers: ~{~S~^, ~}~]~
476 ~@[~@:_ Documentation:~@:_ ~@<~@;~A~:>~]~}"
477 (mapcar (lambda (slotd)
478 (list (sb-mop:slot-definition-name slotd
)
479 (let ((type (sb-mop:slot-definition-type slotd
)))
480 (unless (eq t type
) type
))
481 (let ((alloc (sb-mop:slot-definition-allocation slotd
)))
482 (unless (eq :instance alloc
) alloc
))
483 (sb-mop:slot-definition-initargs slotd
)
484 (sb-mop:slot-definition-initform slotd
)
485 (sb-mop:slot-definition-readers slotd
)
486 (sb-mop:slot-definition-writers slotd
)
487 ;; FIXME: does this get the prefix right?
488 (quiet-doc slotd t
)))
490 (format stream
"~@:_No direct slots."))))
491 (pprint-indent :block
0 stream
)
492 (pprint-newline :mandatory stream
))))))
494 (defun describe-instance (object stream
)
495 (let* ((class (class-of object
))
496 (slotds (sb-mop:class-slots class
))
497 (max-slot-name-length 0)
500 ;; Figure out a good width for the slot-name column.
501 (flet ((adjust-slot-name-length (name)
502 (setf max-slot-name-length
503 (max max-slot-name-length
(length (symbol-name name
))))))
504 (dolist (slotd slotds
)
505 (adjust-slot-name-length (sb-mop:slot-definition-name slotd
))
506 (push slotd
(getf plist
(sb-mop:slot-definition-allocation slotd
))))
507 (setf max-slot-name-length
(min (+ max-slot-name-length
3) 30)))
509 ;; Now that we know the width, we can print.
510 (flet ((describe-slot (name value
)
511 (format stream
"~% ~A~VT = ~A" name max-slot-name-length
512 (prin1-to-line value
))))
513 (sb-pcl::doplist
(allocation slots
) plist
514 (format stream
"~%Slots with ~S allocation:" allocation
)
515 (dolist (slotd (nreverse slots
))
517 (sb-mop:slot-definition-name slotd
)
518 (sb-pcl::slot-value-or-default object
(sb-mop:slot-definition-name slotd
))))))
520 (format stream
"~@:_No slots."))
523 (defun quiet-doc (object type
)
524 (handler-bind ((warning #'muffle-warning
))
525 (documentation object type
)))
527 (defun describe-documentation (object type stream
&optional undoc newline
)
528 (let ((doc (quiet-doc object type
)))
530 (format stream
"~@:_Documentation:~@:_")
531 (pprint-logical-block (stream nil
:per-line-prefix
" ")
534 (format stream
"~@:_(undocumented)")))
536 (pprint-newline :mandatory stream
))))
538 (defun describe-stuff (label list stream
&key
(escape t
))
541 (format stream
"~@:_~A:~@<~;~{ ~S~^,~:_~}~;~:>" label list
)
542 (format stream
"~@:_~A:~@<~;~{ ~A~^,~:_~}~;~:>" label list
))))
544 (defun describe-lambda-list (lambda-list stream
)
545 (let ((*print-circle
* nil
)
548 (format stream
"~@:_Lambda-list: ~:A" lambda-list
)))
550 (defun describe-function-source (function stream
)
551 (if (compiled-function-p function
)
552 (let* ((code (fun-code-header (%fun-fun function
)))
553 (info (sb-kernel:%code-debug-info code
)))
555 (let ((source (sb-c::debug-info-source info
)))
557 (let ((namestring (sb-c::debug-source-namestring source
)))
558 ;; This used to also report the times the source was created
559 ;; and compiled, but that seems more like noise than useful
560 ;; information -- but FWIW that are to be had as
561 ;; SB-C::DEBUG-SOUCE-CREATED/COMPILED.
563 (format stream
"~@:_Source file: ~A" namestring
))
564 ((sb-di:debug-source-form source
)
565 (format stream
"~@:_Source form:~@:_ ~S"
566 (sb-di:debug-source-form source
)))))))))
568 (let ((source (sb-eval:interpreted-function-source-location function
)))
570 (let ((namestring (sb-c:definition-source-location-namestring source
)))
572 (format stream
"~@:_Source file: ~A" namestring
)))))))
574 (defun describe-function (name function stream
)
575 (let ((name (if function
(fun-name function
) name
)))
576 (if (not (or function
(and (legal-fun-name-p name
) (fboundp name
))))
577 ;; Not defined, but possibly the type is declared, or we have
578 ;; compiled calls to it.
579 (when (legal-fun-name-p name
)
580 (multiple-value-bind (from sure
) (info :function
:where-from name
)
581 (when (or (eq :declared from
) (and sure
(eq :assumed from
)))
582 (pprint-logical-block (stream nil
)
583 (format stream
"~%~A names an undefined function" name
)
584 (pprint-indent :block
2 stream
)
585 (format stream
"~@:_~:(~A~) type: ~S"
587 (type-specifier (info :function
:type name
)))))))
589 (multiple-value-bind (fun what lambda-list derived-type declared-type
591 (cond ((and (not function
) (symbolp name
) (special-operator-p name
))
592 (let ((fun (symbol-function name
)))
593 (values fun
"a special operator" (%fun-lambda-list fun
))))
594 ((and (not function
) (symbolp name
) (macro-function name
))
595 (let ((fun (macro-function name
)))
596 (values fun
"a macro" (%fun-lambda-list fun
))))
598 (let* ((fun (or function
(fdefinition name
)))
599 (derived-type (and function
600 (%fun-type function
)))
601 (legal-name-p (legal-fun-name-p name
))
602 (ctype (and legal-name-p
603 (info :function
:type name
)))
604 (type (and ctype
(type-specifier ctype
)))
605 (from (and legal-name-p
606 (info :function
:where-from name
)))
608 ;; Ensure lazy pickup of information
611 (sb-c::maybe-update-info-for-gf name
))
614 (setf declared-type type
))
615 ((and (not derived-type
)
616 (member from
'(:defined-method
:defined
)))
617 (setf derived-type type
)))
619 (setf derived-type
(%fun-type fun
)))
620 (if (typep fun
'standard-generic-function
)
623 (sb-mop:generic-function-lambda-list fun
)
627 (or (sb-mop:generic-function-methods fun
)
630 (if (compiled-function-p fun
)
631 "a compiled function"
632 "an interpreted function")
633 (%fun-lambda-list fun
)
637 (info :function
:inlinep name
)
638 (info :function
:inline-expansion-designator
640 (pprint-logical-block (stream nil
)
642 (format stream
"~%~A names ~A:" name what
)
643 (pprint-indent :block
2 stream
))
644 (describe-lambda-list lambda-list stream
)
646 (format stream
"~@:_Declared type: ~S" declared-type
))
647 (when (and derived-type
648 (not (equal declared-type derived-type
)))
649 (format stream
"~@:_Derived type: ~S" derived-type
))
650 (describe-documentation name
'function stream
)
652 (format stream
"~@:_Inline proclamation: ~
653 ~A (~:[no ~;~]inline expansion available)"
656 (awhen (info :function
:info name
)
657 (awhen (sb-c::decode-ir1-attributes
(sb-c::fun-info-attributes it
))
658 (format stream
"~@:_Known attributes: ~(~{~A~^, ~}~)" it
)))
660 (format stream
"~@:_Method-combination: ~S"
661 (sb-pcl::method-combination-type-name
662 (sb-pcl:generic-function-method-combination fun
)))
663 (cond ((eq :none methods
)
664 (format stream
"~@:_No methods."))
666 (pprint-newline :mandatory stream
)
667 (pprint-logical-block (stream nil
)
668 (format stream
"Methods:")
669 (dolist (method methods
)
670 (pprint-indent :block
2 stream
)
671 (format stream
"~@:_(~A ~{~S ~}~:S)"
673 (method-qualifiers method
)
674 (sb-pcl::unparse-specializers
675 fun
(sb-mop:method-specializers method
)))
676 (pprint-indent :block
4 stream
)
677 (describe-documentation method t stream nil
))))))
678 (describe-function-source fun stream
)
681 (awhen (and (legal-fun-name-p name
) (compiler-macro-function name
))
682 (pprint-logical-block (stream nil
)
683 (format stream
"~@:_~A has a compiler-macro:" name
)
684 (pprint-indent :block
2 stream
)
685 (describe-documentation it t stream
)
686 (describe-function-source it stream
))
688 (when (and (consp name
) (eq 'setf
(car name
)) (not (cddr name
)))
689 (let* ((name2 (second name
))
690 (inverse (info :setf
:inverse name2
))
691 (expander (info :setf
:expander name2
)))
693 (pprint-logical-block (stream nil
)
694 (format stream
"~&~A has setf-expansion: ~S"
696 (pprint-indent :block
2 stream
)
697 (describe-documentation name2
'setf stream
))
700 (pprint-logical-block (stream nil
)
701 (format stream
"~&~A has a complex setf-expansion:"
703 (pprint-indent :block
2 stream
)
704 (describe-lambda-list (%fun-lambda-list expander
) stream
)
705 (describe-documentation name2
'setf stream t
)
706 (describe-function-source expander stream
))
709 (describe-function `(setf ,name
) nil stream
))))