1 ;;;; Inspector for sb-aclrepl
3 ;;;; The documentation, which may or may not apply in its entirety at
4 ;;;; any given time, for this functionality is on the ACL website:
5 ;;;; <http://www.franz.com/support/documentation/6.2/doc/inspector.htm>.
7 ;;;; A summary of inspector navigation is contained in the below *INSPECT-HELP*
10 (cl:in-package #:sb-aclrepl)
12 (eval-when (:compile-toplevel :load-toplevel :execute)
13 (defconstant +default-inspect-length+ 20))
16 ;; stack of parents of inspected object
18 ;; a stack of indices of parent object components
21 ;; FIXME - raw mode isn't currently used in object display
22 (defparameter *current-inspect* nil
24 (defparameter *inspect-raw* nil
25 "Raw mode for object display.")
26 (defparameter *inspect-length* +default-inspect-length+
27 "maximum number of components to print")
28 (defparameter *skip-address-display* nil
29 "Skip displaying addresses of objects.")
31 (defvar *inspect-help*
32 ":istep takes between 0 to 3 arguments.
34 :i redisplay current object
35 :i = redisplay current object
36 :i nil redisplay current object
37 :i ? display this help
38 :i * inspect the current * value
39 :i + <form> inspect the (eval form)
40 :i slot <name> inspect component of object, even if name is an istep cmd
41 :i <index> inspect the numbered component of object
42 :i <name> inspect the named component of object
43 :i <form> evaluation and inspect form
46 :i < inspect previous parent component
47 :i > inspect next parent component
48 :i set <index> <form> set indexed component to evalated form
49 :i print <max> set the maximum number of components to print
50 :i skip <n> skip a number of components when printing
51 :i tree print inspect stack
54 ;;; When *INSPECT-UNBOUND-OBJECT-MARKER* occurs in a parts list, it
55 ;;; indicates that that a slot is unbound.
56 (eval-when (:compile-toplevel :load-toplevel :execute)
57 (defvar *inspect-unbound-object-marker* (gensym "INSPECT-UNBOUND-OBJECT-")))
60 (defun inspector-fun (object input-stream output-stream)
61 (declare (ignore input-stream))
62 (let ((*current-inspect* nil)
64 (*inspect-length* *inspect-length*)
65 (*skip-address-display* nil))
66 (setq object (eval object))
67 (setq *current-inspect* (make-inspect))
68 (reset-stack object "(inspect ...)")
69 (redisplay output-stream)
70 (let ((*input* input-stream)
71 (*output* output-stream))
75 (setq sb-impl::*inspect-fun* #'inspector-fun)
77 (defun istep (args stream)
78 (unless *current-inspect*
79 (setq *current-inspect* (make-inspect)))
82 (when (first args) (read-from-string (first args)))
85 (defun istep-dispatch (args option-string option stream)
87 ((or (string= "=" option-string) (zerop (length args)))
88 (istep-cmd-redisplay stream))
89 ((or (string= "-" option-string) (string= "^" option-string))
90 (istep-cmd-parent stream))
91 ((string= "*" option-string)
92 (istep-cmd-inspect-* stream))
93 ((string= "+" option-string)
94 (istep-cmd-inspect-new-form (read-from-string (second args)) stream))
95 ((or (string= "<" option-string)
96 (string= ">" option-string))
97 (istep-cmd-select-parent-component option-string stream))
98 ((string-equal "set" option-string)
99 (istep-cmd-set (second args) (third args) stream))
100 ((string-equal "raw" option-string)
101 (istep-cmd-set-raw (second args) stream))
102 ((string-equal "q" option-string)
104 ((string-equal "?" option-string)
105 (istep-cmd-help stream))
106 ((string-equal "skip" option-string)
107 (istep-cmd-skip (second args) stream))
108 ((string-equal "tree" option-string)
109 (istep-cmd-tree stream))
110 ((string-equal "print" option-string)
111 (istep-cmd-print (second args) stream))
112 ((string-equal "slot" option-string)
113 (istep-cmd-select-component (read-from-string (second args)) stream))
114 ((or (symbolp option)
116 (istep-cmd-select-component option stream))
118 (istep-cmd-set-stack option stream))))
120 (defun set-current-inspect (inspect)
121 (setq *current-inspect* inspect))
123 (defun reset-stack (&optional object label)
126 (setf (inspect-object-stack *current-inspect*) nil)
127 (setf (inspect-select-stack *current-inspect*) nil))
129 (setf (inspect-object-stack *current-inspect*) (list object))
130 (setf (inspect-select-stack *current-inspect*) (list label)))))
132 (defun output-inspect-note (stream note &rest args)
133 (apply #'format stream note args)
134 (princ #\Newline stream))
137 (inspect-object-stack *current-inspect*))
139 (defun redisplay (stream &optional (skip 0))
140 (display-current stream *inspect-length* skip))
143 ;;; istep command processing
146 (defun istep-cmd-redisplay (stream)
149 (defun istep-cmd-parent (stream)
151 ((> (length (inspect-object-stack *current-inspect*)) 1)
152 (setf (inspect-object-stack *current-inspect*)
153 (cdr (inspect-object-stack *current-inspect*)))
154 (setf (inspect-select-stack *current-inspect*)
155 (cdr (inspect-select-stack *current-inspect*)))
158 (output-inspect-note stream "Object has no parent"))
160 (no-object-msg stream))))
162 (defun istep-cmd-inspect-* (stream)
163 (reset-stack * "(inspect *)")
166 (defun istep-cmd-inspect-new-form (form stream)
167 (inspector-fun (eval form) nil stream))
169 (defun istep-cmd-select-parent-component (option stream)
171 (if (eql (length (stack)) 1)
172 (output-inspect-note stream "Object does not have a parent")
173 (let ((parent (second (stack)))
174 (id (car (inspect-select-stack *current-inspect*))))
175 (multiple-value-bind (position parts)
176 (find-part-id parent id)
177 (let ((new-position (if (string= ">" option)
180 (if (< -1 new-position (parts-count parts))
181 (let* ((value (component-at parts new-position)))
182 (setf (car (inspect-object-stack *current-inspect*))
184 (setf (car (inspect-select-stack *current-inspect*))
185 (id-at parts new-position))
187 (output-inspect-note stream
188 "Parent has no selectable component indexed by ~d"
190 (no-object-msg stream)))
192 (defun istep-cmd-set-raw (option-string stream)
193 (when (inspect-object-stack *current-inspect*)
195 ((null option-string)
196 (setq *inspect-raw* t))
197 ((eq (read-from-string option-string) t)
198 (setq *inspect-raw* t))
199 ((eq (read-from-string option-string) nil)
200 (setq *inspect-raw* nil)))
203 (defun istep-cmd-reset ()
205 (throw 'repl-catcher (values :inspect nil)))
207 (defun istep-cmd-help (stream)
208 (format stream *inspect-help*))
210 (defun istep-cmd-skip (option-string stream)
212 (let ((len (read-from-string option-string)))
213 (if (and (integerp len) (>= len 0))
214 (redisplay stream len)
215 (output-inspect-note stream "Skip length invalid")))
216 (output-inspect-note stream "Skip length missing")))
218 (defun istep-cmd-print (option-string stream)
220 (let ((len (read-from-string option-string)))
221 (if (and (integerp len) (plusp len))
222 (setq *inspect-length* len)
223 (output-inspect-note stream "Cannot set print limit to ~A~%" len)))
224 (output-inspect-note stream "Print length missing")))
226 (defun select-description (select)
229 (format nil "which is componenent number ~d of" select))
231 (format nil "which is the ~a component of" select))
233 (format nil "which was selected by ~A" select))
235 (write-to-string select))))
237 (defun istep-cmd-tree (stream)
238 (let ((stack (inspect-object-stack *current-inspect*)))
241 (output-inspect-note stream "The current object is:")
242 (dotimes (i (length stack))
245 (inspected-description (nth i stack))
247 (nth i (inspect-select-stack *current-inspect*))))))
248 (no-object-msg stream))))
250 (defun istep-cmd-set (id-string value-string stream)
252 (let ((id (when id-string (read-from-string id-string))))
253 (multiple-value-bind (position parts)
254 (find-part-id (car (stack)) id)
258 (let ((new-value (eval (read-from-string value-string))))
259 (let ((result (set-component-value (car (stack))
266 (output-inspect-note stream result))
268 (redisplay stream))))))
271 "Object has no selectable component named by ~A" id))
272 (output-inspect-note stream
273 "Object has no selectable components"))))
274 (no-object-msg stream)))
276 (defun istep-cmd-select-component (id stream)
278 (multiple-value-bind (position parts)
279 (find-part-id (car (stack)) id)
282 (let* ((value (component-at parts position)))
283 (cond ((eq value *inspect-unbound-object-marker*)
284 (output-inspect-note stream "That slot is unbound"))
286 (push value (inspect-object-stack *current-inspect*))
287 (push id (inspect-select-stack *current-inspect*))
288 (redisplay stream)))))
290 (output-inspect-note stream "Object does not contain any subobjects"))
295 stream "Object has no selectable component named ~A"
299 stream "Object has no selectable component indexed by ~d"
301 (no-object-msg stream)))
303 (defun istep-cmd-set-stack (form stream)
304 (reset-stack (eval form) ":i ...")
308 (defun no-object-msg (s)
309 (output-inspect-note s "No object is being inspected"))
311 (defun display-current (s length skip)
313 (let ((inspected (car (stack))))
314 (setq cl:* inspected)
315 (display-inspect inspected s length skip))
320 ;;; aclrepl-specific inspection display
323 (defun display-inspect (object stream &optional length (skip 0))
324 (multiple-value-bind (elements labels count)
325 (inspected-elements object length skip)
327 (format stream "~A" (inspected-description object))
328 (unless (or *skip-address-display*
329 (eq object *inspect-unbound-object-marker*)
330 (characterp object) (typep object 'fixnum))
331 (format stream " at #x~X" (logand
332 (sb-kernel:get-lisp-obj-address object)
333 (lognot sb-vm:lowtag-mask))))
336 (display-labeled-element (elt elements i) (elt labels i) stream))))
338 (defun hex32-label-p (label)
339 (and (consp label) (eq (cdr label) :hex32)))
341 (defun array-label-p (label)
343 (stringp (cdr label))
344 (char= (char (cdr label) 0) #\[)))
346 (defun named-or-array-label-p (label)
348 (not (hex32-label-p label))))
350 (defun display-labeled-element (element label stream)
352 ((eq label :ellipses)
353 (format stream " ..."))
355 (format stream "tail-> ~A" (inspected-description element)))
356 ((named-or-array-label-p label)
358 (if (array-label-p label)
360 "~4,' D ~16,1,1,'-A> ~A")
362 (format nil "~A " (cdr label))
363 (inspected-description element)))
364 ((hex32-label-p label)
365 (format stream "~4,' D-> #x~8,'0X" (car label) element))
367 (format stream "~4,' D-> ~A" label (inspected-description element)))))
369 ;;; THE BEGINNINGS OF AN INSPECTOR API
370 ;;; which can be used to retrieve object descriptions as component values/labels and also
371 ;;; process print length and skip selectors
373 ;;; FUNCTIONS TO CONSIDER FOR EXPORT
377 ;;; INSPECTED-ELEMENTS
378 ;;; INSPECTED-DESCRIPTION
380 ;;; will also need hooks
381 ;;; *inspect-start-inspection*
382 ;;; (maybe. Would setup a window for a GUI inspector)
383 ;;; *inspect-prompt-fun*
384 ;;; *inspect-read-cmd*
386 ;;; and, either an *inspect-process-cmd*, or *inspect-display* hook
387 ;;; That'll depend if choose to have standardized inspector commands such that
388 ;;; (funcall *inspect-read-cmd*) will return a standard command that SBCL will
389 ;;; process and then call the *inspect-display* hook, or if the
390 ;;; *inspect-read-cmd* will return an impl-dependent cmd that sbcl will
391 ;;; send to the contributed inspector for processing and display.
393 (defun find-part-id (object id)
394 "COMPONENT-ID can be an integer or a name of a id.
395 Returns (VALUES POSITION PARTS).
396 POSITION is NIL if the id is invalid or not found."
397 (let* ((parts (inspected-parts object))
398 (name (if (symbolp id) (symbol-name id) id)))
402 (< -1 id (parts-count parts))
403 (not (eq (parts-seq-type parts) :bignum)))
406 (case (parts-seq-type parts)
408 (position name (the list (parts-components parts))
409 :key #'car :test #'string-equal))
410 ((:dotted-list :cyclic-list)
411 (when (string-equal name "tail")
412 (1- (parts-count parts)))))))
415 (defun component-at (parts position)
416 (let ((count (parts-count parts))
417 (components (parts-components parts)))
418 (when (< -1 position count)
419 (case (parts-seq-type parts)
421 (if (= position (1- count))
422 (cdr (last components))
423 (elt components position)))
425 (if (= position (1- count))
427 (elt components position)))
429 (cdr (elt components position)))
431 (aref (the array components) position))
433 (bignum-component-at components position))
435 (elt components position))))))
437 (defun id-at (parts position)
438 (let ((count (parts-count parts)))
439 (when (< -1 position count)
440 (case (parts-seq-type parts)
441 ((:dotted-list :cyclic-list)
442 (if (= position (1- count))
446 (array-index-string position parts))
448 (car (elt (parts-components parts) position)))
452 (defun inspected-elements (object &optional length (skip 0))
453 "Returns elements of an object that have been trimmed and labeled based on
454 length and skip. Returns (VALUES ELEMENTS LABELS ELEMENT-COUNT)
455 where ELEMENTS and LABELS are vectors containing ELEMENT-COUNT items.
456 LABELS elements may be a string, number, cons pair, :tail, or :ellipses.
457 This function may return an ELEMENT-COUNT of up to (+ 3 length) which would
458 include an :ellipses at the beginning, :ellipses at the end,
459 and the last element."
460 (let* ((parts (inspected-parts object))
461 (print-length (if length length (parts-count parts)))
462 (last-part (last-part parts))
463 (last-requested (last-requested parts print-length skip))
464 (element-count (compute-elements-count parts print-length skip))
465 (first-to (if (first-element-ellipses-p parts skip) 1 0))
466 (elements (when (plusp element-count) (make-array element-count)))
467 (labels (when (plusp element-count) (make-array element-count))))
468 (when (plusp element-count)
469 ;; possible first ellipses
470 (when (first-element-ellipses-p parts skip)
471 (set-element-values elements labels 0 nil :ellipses))
474 ((> i (- last-requested skip)))
475 (set-element elements labels parts (+ i first-to) (+ i skip)))
476 ;; last parts value if needed
477 (when (< last-requested last-part)
478 (set-element elements labels parts (- element-count 1) last-part))
479 ;; ending ellipses or next to last parts value if needed
480 (when (< last-requested (1- last-part))
481 (if (= last-requested (- last-part 2))
482 (set-element elements labels parts (- element-count 2) (1- last-part))
483 (set-element-values elements labels (- element-count 2) nil :ellipses))))
484 (values elements labels element-count)))
486 (defun last-requested (parts print skip)
487 (min (1- (parts-count parts)) (+ skip print -1)))
489 (defun last-part (parts)
490 (1- (parts-count parts)))
492 (defun compute-elements-count (parts length skip)
493 "Compute the number of elements in parts given the print length and skip."
494 (let ((element-count (min (parts-count parts) length
495 (max 0 (- (parts-count parts) skip)))))
496 (when (and (plusp (parts-count parts)) (plusp skip)) ; starting ellipses
497 (incf element-count))
498 (when (< (last-requested parts length skip)
499 (last-part parts)) ; last value
501 (when (< (last-requested parts length skip)
502 (1- (last-part parts))) ; ending ellipses
503 (incf element-count)))
506 (defun set-element (elements labels parts to-index from-index)
507 (set-element-values elements labels to-index (component-at parts from-index)
508 (label-at parts from-index)))
510 (defun set-element-values (elements labels index element label)
511 (setf (aref elements index) element)
512 (setf (aref labels index) label))
514 (defun first-element-ellipses-p (parts skip)
515 (and (parts-count parts) (plusp skip)))
517 (defun label-at (parts position)
518 "Helper function for inspected-elements. Conses the
519 position with the label if the label is a string."
520 (let ((id (id-at parts position)))
524 ((eq (parts-seq-type parts) :bignum)
525 (cons position :hex32))
529 (defun array-index-string (index parts)
530 "Formats an array index in row major format."
531 (let ((rev-dimensions (parts-seq-hint parts)))
532 (if (null rev-dimensions)
535 (dolist (dim rev-dimensions)
536 (multiple-value-bind (q r) (floor index dim)
539 (format nil "[~W~{,~W~}]" (car list) (cdr list))))))
542 ;;; INSPECTED-DESCRIPTION
544 ;;; Accepts an object and returns
545 ;;; DESCRIPTION is a summary description of the destructured object,
546 ;;; e.g. "the object is a CONS".
548 (defgeneric inspected-description (object))
550 (defmethod inspected-description ((object symbol))
551 (format nil "the symbol ~A" object))
553 (defmethod inspected-description ((object structure-object))
554 (format nil "~W" (find-class (type-of object))))
556 (defmethod inspected-description ((object package))
557 (format nil "the ~A package" (package-name object)))
559 (defmethod inspected-description ((object standard-object))
560 (format nil "~W" (class-of object)))
562 (defmethod inspected-description ((object sb-kernel:funcallable-instance))
563 (format nil "a funcallable-instance of type ~S" (type-of object)))
565 (defmethod inspected-description ((object function))
566 (format nil "~S" object) nil)
568 (defmethod inspected-description ((object vector))
569 (declare (vector object))
570 (format nil "a ~:[~;displaced ~]vector (~W)"
571 (and (sb-kernel:array-header-p object)
572 (sb-kernel:%array-displaced-p object))
575 (defmethod inspected-description ((object simple-vector))
576 (declare (simple-vector object))
577 (format nil "a simple ~A vector (~D)"
578 (array-element-type object)
581 (defmethod inspected-description ((object array))
582 (declare (array object))
583 (format nil "~:[A displaced~;An~] array of ~A with dimensions ~W"
584 (and (sb-kernel:array-header-p object)
585 (sb-kernel:%array-displaced-p object))
586 (array-element-type object)
587 (array-dimensions object)))
589 (defun simple-cons-pair-p (object)
592 (defmethod inspected-description ((object cons))
593 (if (simple-cons-pair-p object)
595 (inspected-description-of-nontrivial-list object)))
597 (defun cons-safe-length (object)
598 "Returns (VALUES LENGTH LIST-TYPE) where length is the number of
599 cons cells and LIST-TYPE is :normal, :dotted, or :cyclic"
600 (do ((length 1 (1+ length))
601 (lst (cdr object) (cdr lst)))
602 ((or (not (consp lst))
606 (values length :normal))
608 (values length :dotted))
610 (values length :cyclic))))
611 ;; nothing to do in body
614 (defun inspected-description-of-nontrivial-list (object)
615 (multiple-value-bind (length list-type) (cons-safe-length object)
616 (format nil "a ~A list with ~D element~:*~P~A"
617 (string-downcase (symbol-name list-type)) length
619 ((:dotted :cyclic) "+tail")
622 (defun ref32-hexstr (obj &optional (offset 0))
623 (format nil "~8,'0X" (ref32 obj offset)))
625 (defun ref32 (obj &optional (offset 0))
626 (sb-sys::without-gcing
629 (logand (sb-kernel:get-lisp-obj-address obj) (lognot sb-vm:lowtag-mask)))
632 (defun description-maybe-internals (fmt objects internal-fmt &rest args)
633 (let ((base (apply #'format nil fmt objects)))
634 (if *skip-address-display*
637 base " " (apply #'format nil internal-fmt args)))))
639 (defmethod inspected-description ((object double-float))
640 (description-maybe-internals "double-float ~W" (list object)
642 (ref32-hexstr object 12)
643 (ref32-hexstr object 8)))
645 (defmethod inspected-description ((object single-float))
646 (description-maybe-internals "single-float ~W" (list object)
648 (ref32-hexstr object 4)))
650 (defmethod inspected-description ((object fixnum))
651 (description-maybe-internals "fixnum ~W" (list object)
653 (ash object (1- sb-vm:n-lowtag-bits))))
655 (defmethod inspected-description ((object complex))
656 (format nil "complex number ~W" object))
658 (defmethod inspected-description ((object simple-string))
659 (format nil "a simple-string (~W) ~W" (length object) object))
661 (defun bignum-words (bignum)
662 "Return the number of 32-bit words in a bignum"
664 (logand (ref32 bignum)
665 (lognot sb-vm:widetag-mask))
666 (- sb-vm:n-widetag-bits)))
668 (defun bignum-component-at (bignum offset)
669 "Return the 32-bit word at 32-bit wide offset"
670 (ref32 bignum (* 4 (1+ offset))))
672 (defmethod inspected-description ((object bignum))
673 (format nil "bignum ~W with ~D 32-bit word~:*~P" object
674 (bignum-words object)))
676 (defmethod inspected-description ((object ratio))
677 (format nil "ratio ~W" object))
679 (defmethod inspected-description ((object character))
680 ;; FIXME: This will need to change as and when we get more characters
681 ;; than just the 256 we have today.
682 (description-maybe-internals "character ~W char-code #x~2,'0X"
683 (list object (char-code object))
685 (logior sb-vm:base-char-widetag
686 (ash (char-code object)
687 sb-vm:n-widetag-bits))))
689 (defmethod inspected-description ((object t))
690 (format nil "a generic object ~W" object))
692 (defmethod inspected-description ((object (eql *inspect-unbound-object-marker*)))
698 ;;; Accepts the arguments OBJECT LENGTH SKIP and returns,
699 ;;; (LIST COMPONENTS SEQ-TYPE COUNT SEQ-HINT)
702 ;;; COMPONENTS are the component parts of OBJECT (whose
703 ;;; representation is determined by SEQ-TYPE). Except for the
704 ;;; SEQ-TYPE :named and :array, components is just the OBJECT itself
706 ;;; SEQ-TYPE determines what representation is used for components
708 ;;; If SEQ-TYPE is :named, then each element is (CONS NAME VALUE)
709 ;;; If SEQ-TYPE is :dotted-list, then each element is just value,
710 ;;; but the last element must be retrieved by
711 ;;; (cdr (last components))
712 ;;; If SEQ-TYPE is :cylic-list, then each element is just value,
713 ;;; If SEQ-TYPE is :list, then each element is a value of an array
714 ;;; If SEQ-TYPE is :vector, then each element is a value of an vector
715 ;;; If SEQ-TYPE is :array, then each element is a value of an array
716 ;;; with rank >= 2. The
717 ;;; If SEQ-TYPE is :bignum, then object is just a bignum and not a
720 ;;; COUNT is the total number of components in the OBJECT
722 ;;; SEQ-HINT is a seq-type dependent hint. Used by SEQ-TYPE :array
723 ;;; to hold the reverse-dimensions of the orignal array.
725 (declaim (inline parts-components))
726 (defun parts-components (parts)
729 (declaim (inline parts-count))
730 (defun parts-count (parts)
733 (declaim (inline parts-seq-type))
734 (defun parts-seq-type (parts)
737 (declaim (inline parts-seq-hint))
738 (defun parts-seq-hint (parts)
741 (defgeneric inspected-parts (object)
744 (defmethod inspected-parts ((object symbol))
746 (list (cons "NAME" (symbol-name object))
747 (cons "PACKAGE" (symbol-package object))
748 (cons "VALUE" (if (boundp object)
749 (symbol-value object)
750 *inspect-unbound-object-marker*))
751 (cons "FUNCTION" (if (fboundp object)
752 (symbol-function object)
753 *inspect-unbound-object-marker*))
754 (cons "PLIST" (symbol-plist object)))))
755 (list components (length components) :named nil)))
757 (defun inspected-structure-parts (object)
758 (let ((components-list '())
759 (info (sb-kernel:layout-info (sb-kernel:layout-of object))))
760 (when (sb-kernel::defstruct-description-p info)
761 (dolist (dd-slot (sb-kernel:dd-slots info) (nreverse components-list))
762 (push (cons (string (sb-kernel:dsd-name dd-slot))
763 (funcall (sb-kernel:dsd-accessor-name dd-slot) object))
766 (defmethod inspected-parts ((object structure-object))
767 (let ((components (inspected-structure-parts object)))
768 (list components (length components) :named nil)))
770 (defun inspected-standard-object-parts (object)
771 (let ((components nil)
772 (class-slots (sb-pcl::class-slots (class-of object))))
773 (dolist (class-slot class-slots components)
774 (let* ((slot-name (slot-value class-slot 'sb-pcl::name))
775 (slot-value (if (slot-boundp object slot-name)
776 (slot-value object slot-name)
777 *inspect-unbound-object-marker*)))
778 (push (cons (symbol-name slot-name) slot-value) components)))))
781 (defmethod inspected-parts ((object standard-object))
782 (let ((components (inspected-standard-object-parts object)))
783 (list components (length components) :named nil)))
785 (defmethod inspected-parts ((object sb-kernel:funcallable-instance))
786 (let ((components (inspected-structure-parts object)))
787 (list components (length components) :named nil)))
789 (defmethod inspected-parts ((object function))
790 (let* ((type (sb-kernel:widetag-of object))
791 (object (if (= type sb-vm:closure-header-widetag)
792 (sb-kernel:%closure-fun object)
794 (components (list (cons "arglist"
795 (sb-kernel:%simple-fun-arglist object)))))
796 (list components (length components) :named nil)))
798 (defmethod inspected-parts ((object vector))
799 (list object (length object) :vector nil))
801 (defmethod inspected-parts ((object array))
802 (let ((size (array-total-size object)))
803 (list (make-array size :displaced-to object)
806 (reverse (array-dimensions object)))))
808 (defmethod inspected-parts ((object cons))
809 (if (simple-cons-pair-p object)
810 (inspected-parts-of-simple-cons object)
811 (inspected-parts-of-nontrivial-list object)))
813 (defun inspected-parts-of-simple-cons (object)
814 (let ((components (list (cons "car" (car object))
815 (cons "cdr" (cdr object)))))
816 (list components 2 :named nil)))
818 (defun inspected-parts-of-nontrivial-list (object)
819 (multiple-value-bind (count list-type) (cons-safe-length object)
822 (list object count :list nil))
824 (list object (1+ count) :cyclic-list nil))
826 ;; count tail element
827 (list object (1+ count) :dotted-list nil)))))
829 (defmethod inspected-parts ((object complex))
830 (let ((components (list (cons "real" (realpart object))
831 (cons "imag" (imagpart object)))))
832 (list components (length components) :named nil)))
834 (defmethod inspected-parts ((object ratio))
835 (let ((components (list (cons "numerator" (numerator object))
836 (cons "denominator" (denominator object)))))
837 (list components (length components) :named nil)))
839 (defmethod inspected-parts ((object bignum))
840 (list object (bignum-words object) :bignum nil))
842 (defmethod inspected-parts ((object t))
843 (list nil 0 nil nil))
846 ;; FIXME - implement setting of component values
848 (defgeneric set-component-value (object component-id value element))
850 (defmethod set-component-value ((object cons) id value element)
851 (format nil "Cons object does not support setting of component ~A" id))
853 (defmethod set-component-value ((object array) id value element)
854 (format nil "Array object does not support setting of component ~A" id))
856 (defmethod set-component-value ((object symbol) id value element)
857 (format nil "Symbol object does not support setting of component ~A" id))
859 (defmethod set-component-value ((object structure-object) id value element)
860 (format nil "Structure object does not support setting of component ~A" id))
862 (defmethod set-component-value ((object standard-object) id value element)
863 (format nil "Standard object does not support setting of component ~A" id))
865 (defmethod set-component-value ((object t) id value element)
866 (format nil "Object does not support setting of component ~A" id))