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))
15 (defstruct (%inspect
(:constructor make-inspect
)
16 (:conc-name inspect-
))
17 ;; stack of parents of inspected object
19 ;; a stack of indices of parent object components
22 ;; FIXME - raw mode isn't currently used in object display
23 (defparameter *current-inspect
* nil
25 (defparameter *inspect-raw
* nil
26 "Raw mode for object display.")
27 (defparameter *inspect-length
* +default-inspect-length
+
28 "maximum number of components to print")
29 (defparameter *skip-address-display
* nil
30 "Skip displaying addresses of objects.")
32 (defvar *inspect-help
*
33 ":istep takes between 0 to 3 arguments.
35 :i redisplay current object
36 :i = redisplay current object
37 :i nil redisplay current object
38 :i ? display this help
39 :i * inspect the current * value
40 :i + <form> inspect the (eval form)
41 :i slot <name> inspect component of object, even if name is an istep cmd
42 :i <index> inspect the numbered component of object
43 :i <name> inspect the named component of object
44 :i <form> evaluation and inspect form
47 :i < inspect previous parent component
48 :i > inspect next parent component
49 :i set <index> <form> set indexed component to evalated form
50 :i print <max> set the maximum number of components to print
51 :i skip <n> skip a number of components when printing
52 :i tree print inspect stack
55 ;;; When *INSPECT-UNBOUND-OBJECT-MARKER* occurs in a parts list, it
56 ;;; indicates that that a slot is unbound.
57 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
58 (defvar *inspect-unbound-object-marker
* (gensym "INSPECT-UNBOUND-OBJECT-")))
61 (defun inspector-fun (object input-stream output-stream
)
62 (let ((*current-inspect
* nil
)
64 (*inspect-length
* *inspect-length
*)
65 (*skip-address-display
* nil
))
66 (setq *current-inspect
* (make-inspect))
67 (reset-stack object
"(inspect ...)")
68 (redisplay output-stream
)
69 (let ((*input
* input-stream
)
70 (*output
* output-stream
))
74 (setq sb-impl
::*inspect-fun
* #'inspector-fun
)
76 (defun istep (args stream
)
77 (unless *current-inspect
*
78 (setq *current-inspect
* (make-inspect)))
81 (when (first args
) (read-from-string (first args
)))
84 (defun istep-dispatch (args option-string option stream
)
86 ((or (string= "=" option-string
) (zerop (length args
)))
87 (istep-cmd-redisplay stream
))
88 ((or (string= "-" option-string
) (string= "^" option-string
))
89 (istep-cmd-parent stream
))
90 ((string= "*" option-string
)
91 (istep-cmd-inspect-* stream
))
92 ((string= "+" option-string
)
93 (istep-cmd-inspect-new-form (read-from-string (second args
)) stream
))
94 ((or (string= "<" option-string
)
95 (string= ">" option-string
))
96 (istep-cmd-select-parent-component option-string stream
))
97 ((string-equal "set" option-string
)
98 (istep-cmd-set (second args
) (third args
) stream
))
99 ((string-equal "raw" option-string
)
100 (istep-cmd-set-raw (second args
) stream
))
101 ((string-equal "q" option-string
)
103 ((string-equal "?" option-string
)
104 (istep-cmd-help stream
))
105 ((string-equal "skip" option-string
)
106 (istep-cmd-skip (second args
) stream
))
107 ((string-equal "tree" option-string
)
108 (istep-cmd-tree stream
))
109 ((string-equal "print" option-string
)
110 (istep-cmd-print (second args
) stream
))
111 ((string-equal "slot" option-string
)
112 (istep-cmd-select-component (read-from-string (second args
)) stream
))
113 ((or (symbolp option
)
115 (istep-cmd-select-component option stream
))
117 (istep-cmd-set-stack option stream
))))
119 (defun set-current-inspect (inspect)
120 (setq *current-inspect
* inspect
))
122 (defun reset-stack (&optional object label
)
125 (setf (inspect-object-stack *current-inspect
*) nil
)
126 (setf (inspect-select-stack *current-inspect
*) nil
))
128 (setf (inspect-object-stack *current-inspect
*) (list object
))
129 (setf (inspect-select-stack *current-inspect
*) (list label
)))))
131 (defun output-inspect-note (stream note
&rest args
)
132 (apply #'format stream note args
)
133 (princ #\Newline stream
))
136 (inspect-object-stack *current-inspect
*))
138 (defun redisplay (stream &optional
(skip 0))
139 (display-current stream
*inspect-length
* skip
))
143 ;;; Accepts the arguments OBJECT LENGTH SKIP and returns,
144 ;;; (LIST COMPONENTS SEQ-TYPE COUNT SEQ-HINT)
147 ;;; COMPONENTS are the component parts of OBJECT (whose
148 ;;; representation is determined by SEQ-TYPE). Except for the
149 ;;; SEQ-TYPE :named and :array, components is just the OBJECT itself
151 ;;; SEQ-TYPE determines what representation is used for components
153 ;;; If SEQ-TYPE is :named, then each element is (CONS NAME VALUE)
154 ;;; If SEQ-TYPE is :dotted-list, then each element is just value,
155 ;;; but the last element must be retrieved by
156 ;;; (cdr (last components))
157 ;;; If SEQ-TYPE is :cylic-list, then each element is just value,
158 ;;; If SEQ-TYPE is :list, then each element is a value of an array
159 ;;; If SEQ-TYPE is :vector, then each element is a value of an vector
160 ;;; If SEQ-TYPE is :array, then each element is a value of an array
161 ;;; with rank >= 2. The
162 ;;; If SEQ-TYPE is :bignum, then object is just a bignum and not a
165 ;;; COUNT is the total number of components in the OBJECT
167 ;;; SEQ-HINT is a seq-type dependent hint. Used by SEQ-TYPE :array
168 ;;; to hold the reverse-dimensions of the orignal array.
170 (declaim (inline parts-components
))
171 (defun parts-components (parts)
174 (declaim (inline parts-count
))
175 (defun parts-count (parts)
178 (declaim (inline parts-seq-type
))
179 (defun parts-seq-type (parts)
182 (declaim (inline parts-seq-hint
))
183 (defun parts-seq-hint (parts)
187 ;;; istep command processing
190 (defun istep-cmd-redisplay (stream)
193 (defun istep-cmd-parent (stream)
195 ((> (length (inspect-object-stack *current-inspect
*)) 1)
196 (setf (inspect-object-stack *current-inspect
*)
197 (cdr (inspect-object-stack *current-inspect
*)))
198 (setf (inspect-select-stack *current-inspect
*)
199 (cdr (inspect-select-stack *current-inspect
*)))
202 (output-inspect-note stream
"Object has no parent"))
204 (no-object-msg stream
))))
206 (defun istep-cmd-inspect-* (stream)
207 (reset-stack * "(inspect *)")
210 (defun istep-cmd-inspect-new-form (form stream
)
211 (inspector-fun (eval form
) nil stream
))
213 (defun istep-cmd-select-parent-component (option stream
)
215 (if (eql (length (stack)) 1)
216 (output-inspect-note stream
"Object does not have a parent")
217 (let ((parent (second (stack)))
218 (id (car (inspect-select-stack *current-inspect
*))))
219 (multiple-value-bind (position parts
)
220 (find-part-id parent id
)
221 (let ((new-position (if (string= ">" option
)
224 (if (< -
1 new-position
(parts-count parts
))
225 (let* ((value (component-at parts new-position
)))
226 (setf (car (inspect-object-stack *current-inspect
*))
228 (setf (car (inspect-select-stack *current-inspect
*))
229 (id-at parts new-position
))
231 (output-inspect-note stream
232 "Parent has no selectable component indexed by ~d"
234 (no-object-msg stream
)))
236 (defun istep-cmd-set-raw (option-string stream
)
237 (when (inspect-object-stack *current-inspect
*)
239 ((null option-string
)
240 (setq *inspect-raw
* t
))
241 ((eq (read-from-string option-string
) t
)
242 (setq *inspect-raw
* t
))
243 ((eq (read-from-string option-string
) nil
)
244 (setq *inspect-raw
* nil
)))
247 (defun istep-cmd-reset ()
249 (throw 'repl-catcher
(values :inspect nil
)))
251 (defun istep-cmd-help (stream)
252 (format stream
*inspect-help
*))
254 (defun istep-cmd-skip (option-string stream
)
256 (let ((len (read-from-string option-string
)))
257 (if (and (integerp len
) (>= len
0))
258 (redisplay stream len
)
259 (output-inspect-note stream
"Skip length invalid")))
260 (output-inspect-note stream
"Skip length missing")))
262 (defun istep-cmd-print (option-string stream
)
264 (let ((len (read-from-string option-string
)))
265 (if (and (integerp len
) (plusp len
))
266 (setq *inspect-length
* len
)
267 (output-inspect-note stream
"Cannot set print limit to ~A~%" len
)))
268 (output-inspect-note stream
"Print length missing")))
270 (defun select-description (select)
273 (format nil
"which is componenent number ~d of" select
))
275 (format nil
"which is the ~a component of" select
))
277 (format nil
"which was selected by ~A" select
))
279 (write-to-string select
))))
281 (defun istep-cmd-tree (stream)
282 (let ((stack (inspect-object-stack *current-inspect
*)))
285 (output-inspect-note stream
"The current object is:")
286 (dotimes (i (length stack
))
289 (inspected-description (nth i stack
))
291 (nth i
(inspect-select-stack *current-inspect
*))))))
292 (no-object-msg stream
))))
294 (defun istep-cmd-set (id-string value-string stream
)
296 (let ((id (when id-string
(read-from-string id-string
))))
297 (multiple-value-bind (position parts
)
298 (find-part-id (car (stack)) id
)
302 (let ((new-value (eval (read-from-string value-string
))))
303 (let ((result (set-component-value (car (stack))
310 (output-inspect-note stream result
))
312 (redisplay stream
))))))
315 "Object has no selectable component named by ~A" id
))
316 (output-inspect-note stream
317 "Object has no selectable components"))))
318 (no-object-msg stream
)))
320 (defun istep-cmd-select-component (id stream
)
322 (multiple-value-bind (position parts
)
323 (find-part-id (car (stack)) id
)
326 (let* ((value (component-at parts position
)))
327 (cond ((eq value
*inspect-unbound-object-marker
*)
328 (output-inspect-note stream
"That slot is unbound"))
330 (push value
(inspect-object-stack *current-inspect
*))
331 (push id
(inspect-select-stack *current-inspect
*))
332 (redisplay stream
)))))
334 (output-inspect-note stream
"Object does not contain any subobjects"))
339 stream
"Object has no selectable component named ~A"
343 stream
"Object has no selectable component indexed by ~d"
345 (no-object-msg stream
)))
347 (defun istep-cmd-set-stack (form stream
)
348 (reset-stack (eval form
) ":i ...")
352 (defun no-object-msg (s)
353 (output-inspect-note s
"No object is being inspected"))
355 (defun display-current (s length skip
)
357 (let ((inspected (car (stack))))
358 (setq cl
:* inspected
)
359 (display-inspect inspected s length skip
))
364 ;;; aclrepl-specific inspection display
367 (defun display-inspect (object stream
&optional length
(skip 0))
368 (multiple-value-bind (elements labels count
)
369 (inspected-elements object length skip
)
371 (format stream
"~A" (inspected-description object
))
372 (unless (or *skip-address-display
*
373 (eq object
*inspect-unbound-object-marker
*)
374 (and (= sb-vm
::n-word-bits
64) (typep object
'single-float
))
375 (characterp object
) (typep object
'fixnum
))
376 (write-string " at #x" stream
)
377 (format stream
(n-word-bits-hex-format)
378 (logand (sb-kernel:get-lisp-obj-address object
)
379 (lognot sb-vm
:lowtag-mask
))))
382 (display-labeled-element (elt elements i
) (elt labels i
) stream
))))
384 (defun array-label-p (label)
386 (stringp (cdr label
))
387 (char= (char (cdr label
) 0) #\
[)))
389 (defun named-or-array-label-p (label)
390 (and (consp label
) (not (hex-label-p label
))))
392 (defun hex-label-p (label &optional width
)
395 (32 (eq (cdr label
) :hex32
))
396 (64 (eq (cdr label
) :hex64
))
397 (t (or (eq (cdr label
) :hex32
)
398 (eq (cdr label
) :hex64
))))))
400 (defun display-labeled-element (element label stream
)
402 ((eq label
:ellipses
)
403 (format stream
" ..."))
405 (format stream
"tail-> ~A" (inspected-description element
)))
406 ((named-or-array-label-p label
)
408 (if (array-label-p label
)
410 "~4,' D ~16,1,1,'-A> ~A")
412 (format nil
"~A " (cdr label
))
413 (inspected-description element
)))
414 ((hex-label-p label
32)
415 (format stream
"~4,' D-> #x~8,'0X" (car label
) element
))
416 ((hex-label-p label
64)
417 (format stream
"~4,' D-> #x~16,'0X" (car label
) element
))
419 (format stream
"~4,' D-> ~A" label
(inspected-description element
)))))
421 ;;; THE BEGINNINGS OF AN INSPECTOR API
422 ;;; which can be used to retrieve object descriptions as component values/labels and also
423 ;;; process print length and skip selectors
425 ;;; FUNCTIONS TO CONSIDER FOR EXPORT
429 ;;; INSPECTED-ELEMENTS
430 ;;; INSPECTED-DESCRIPTION
432 ;;; will also need hooks
433 ;;; *inspect-start-inspection*
434 ;;; (maybe. Would setup a window for a GUI inspector)
435 ;;; *inspect-prompt-fun*
436 ;;; *inspect-read-cmd*
438 ;;; and, either an *inspect-process-cmd*, or *inspect-display* hook
439 ;;; That'll depend if choose to have standardized inspector commands such that
440 ;;; (funcall *inspect-read-cmd*) will return a standard command that SBCL will
441 ;;; process and then call the *inspect-display* hook, or if the
442 ;;; *inspect-read-cmd* will return an impl-dependent cmd that sbcl will
443 ;;; send to the contributed inspector for processing and display.
445 (defun find-part-id (object id
)
446 "COMPONENT-ID can be an integer or a name of a id.
447 Returns (VALUES POSITION PARTS).
448 POSITION is NIL if the id is invalid or not found."
449 (let* ((parts (inspected-parts object
))
450 (name (if (symbolp id
) (symbol-name id
) id
)))
454 (< -
1 id
(parts-count parts
))
455 (not (eq (parts-seq-type parts
) :bignum
)))
458 (case (parts-seq-type parts
)
460 (position name
(the list
(parts-components parts
))
461 :key
#'car
:test
#'string-equal
))
462 ((:dotted-list
:cyclic-list
)
463 (when (string-equal name
"tail")
464 (1- (parts-count parts
)))))))
467 (defun component-at (parts position
)
468 (let ((count (parts-count parts
))
469 (components (parts-components parts
)))
470 (when (< -
1 position count
)
471 (case (parts-seq-type parts
)
473 (if (= position
(1- count
))
474 (cdr (last components
))
475 (elt components position
)))
477 (if (= position
(1- count
))
479 (elt components position
)))
481 (cdr (elt components position
)))
483 (aref (the array components
) position
))
485 (bignum-component-at components position
))
487 (elt components position
))))))
489 (defun id-at (parts position
)
490 (let ((count (parts-count parts
)))
491 (when (< -
1 position count
)
492 (case (parts-seq-type parts
)
493 ((:dotted-list
:cyclic-list
)
494 (if (= position
(1- count
))
498 (array-index-string position parts
))
500 (car (elt (parts-components parts
) position
)))
504 (defun inspected-elements (object &optional length
(skip 0))
505 "Returns elements of an object that have been trimmed and labeled based on
506 length and skip. Returns (VALUES ELEMENTS LABELS ELEMENT-COUNT)
507 where ELEMENTS and LABELS are vectors containing ELEMENT-COUNT items.
508 LABELS elements may be a string, number, cons pair, :tail, or :ellipses.
509 This function may return an ELEMENT-COUNT of up to (+ 3 length) which would
510 include an :ellipses at the beginning, :ellipses at the end,
511 and the last element."
512 (let* ((parts (inspected-parts object
))
513 (print-length (if length length
(parts-count parts
)))
514 (last-part (last-part parts
))
515 (last-requested (last-requested parts print-length skip
))
516 (element-count (compute-elements-count parts print-length skip
))
517 (first-to (if (first-element-ellipses-p parts skip
) 1 0))
518 (elements (when (plusp element-count
) (make-array element-count
)))
519 (labels (when (plusp element-count
) (make-array element-count
))))
520 (when (plusp element-count
)
521 ;; possible first ellipses
522 (when (first-element-ellipses-p parts skip
)
523 (set-element-values elements labels
0 nil
:ellipses
))
526 ((> i
(- last-requested skip
)))
527 (set-element elements labels parts
(+ i first-to
) (+ i skip
)))
528 ;; last parts value if needed
529 (when (< last-requested last-part
)
530 (set-element elements labels parts
(- element-count
1) last-part
))
531 ;; ending ellipses or next to last parts value if needed
532 (when (< last-requested
(1- last-part
))
533 (if (= last-requested
(- last-part
2))
534 (set-element elements labels parts
(- element-count
2) (1- last-part
))
535 (set-element-values elements labels
(- element-count
2) nil
:ellipses
))))
536 (values elements labels element-count
)))
538 (defun last-requested (parts print skip
)
539 (min (1- (parts-count parts
)) (+ skip print -
1)))
541 (defun last-part (parts)
542 (1- (parts-count parts
)))
544 (defun compute-elements-count (parts length skip
)
545 "Compute the number of elements in parts given the print length and skip."
546 (let ((element-count (min (parts-count parts
) length
547 (max 0 (- (parts-count parts
) skip
)))))
548 (when (and (plusp (parts-count parts
)) (plusp skip
)) ; starting ellipses
549 (incf element-count
))
550 (when (< (last-requested parts length skip
)
551 (last-part parts
)) ; last value
553 (when (< (last-requested parts length skip
)
554 (1- (last-part parts
))) ; ending ellipses
555 (incf element-count
)))
558 (defun set-element (elements labels parts to-index from-index
)
559 (set-element-values elements labels to-index
(component-at parts from-index
)
560 (label-at parts from-index
)))
562 (defun set-element-values (elements labels index element label
)
563 (setf (aref elements index
) element
)
564 (setf (aref labels index
) label
))
566 (defun first-element-ellipses-p (parts skip
)
567 (and (parts-count parts
) (plusp skip
)))
569 (defun label-at (parts position
)
570 "Helper function for inspected-elements. Conses the
571 position with the label if the label is a string."
572 (let ((id (id-at parts position
)))
576 ((eq (parts-seq-type parts
) :bignum
)
577 (cons position
(case sb-vm
::n-word-bits
583 (defun array-index-string (index parts
)
584 "Formats an array index in row major format."
585 (let ((rev-dimensions (parts-seq-hint parts
)))
586 (if (null rev-dimensions
)
589 (dolist (dim rev-dimensions
)
590 (multiple-value-bind (q r
) (floor index dim
)
593 (format nil
"[~W~{,~W~}]" (car list
) (cdr list
))))))
596 ;;; INSPECTED-DESCRIPTION
598 ;;; Accepts an object and returns
599 ;;; DESCRIPTION is a summary description of the destructured object,
600 ;;; e.g. "the object is a CONS".
602 (defgeneric inspected-description
(object))
604 (defmethod inspected-description ((object symbol
))
605 (format nil
"the symbol ~A" object
))
607 (defmethod inspected-description ((object structure-object
))
608 (format nil
"~W" (find-class (type-of object
))))
610 (defmethod inspected-description ((object package
))
611 (format nil
"the ~A package" (package-name object
)))
613 (defmethod inspected-description ((object standard-object
))
614 (format nil
"~W" (class-of object
)))
616 (defmethod inspected-description ((object function
))
617 (format nil
"~S" object
) nil
)
619 (defmethod inspected-description ((object vector
))
620 (declare (vector object
))
621 (format nil
"a ~:[~;displaced ~]vector (~W)"
622 (and (sb-kernel:array-header-p object
)
623 (sb-kernel:%array-displaced-p object
))
626 (defmethod inspected-description ((object simple-vector
))
627 (declare (simple-vector object
))
628 (format nil
"a simple ~A vector (~D)"
629 (array-element-type object
)
632 (defmethod inspected-description ((object array
))
633 (declare (array object
))
634 (format nil
"~:[A displaced~;An~] array of ~A with dimensions ~W"
635 (and (sb-kernel:array-header-p object
)
636 (sb-kernel:%array-displaced-p object
))
637 (array-element-type object
)
638 (array-dimensions object
)))
640 (defun simple-cons-pair-p (object)
643 (defmethod inspected-description ((object cons
))
644 (if (simple-cons-pair-p object
)
646 (inspected-description-of-nontrivial-list object
)))
648 (defun cons-safe-length (object)
649 "Returns (VALUES LENGTH LIST-TYPE) where length is the number of
650 cons cells and LIST-TYPE is :normal, :dotted, or :cyclic"
651 (do ((length 1 (1+ length
))
652 (lst (cdr object
) (cdr lst
)))
653 ((or (not (consp lst
))
657 (values length
:normal
))
659 (values length
:dotted
))
661 (values length
:cyclic
))))
662 ;; nothing to do in body
665 (defun inspected-description-of-nontrivial-list (object)
666 (multiple-value-bind (length list-type
) (cons-safe-length object
)
667 (format nil
"a ~A list with ~D element~:*~P~A"
668 (string-downcase (symbol-name list-type
)) length
670 ((:dotted
:cyclic
) "+tail")
673 (defun n-word-bits-hex-format ()
674 (case sb-vm
::n-word-bits
679 (defun ref32-hexstr (obj &optional
(offset 0))
680 (format nil
"~8,'0X" (ref32 obj offset
)))
682 (defun ref32 (obj &optional
(offset 0))
683 (sb-sys::without-gcing
686 (logand (sb-kernel:get-lisp-obj-address obj
) (lognot sb-vm
:lowtag-mask
)))
689 (defun description-maybe-internals (fmt objects internal-fmt
&rest args
)
690 (let ((base (apply #'format nil fmt objects
)))
691 (if *skip-address-display
*
694 base
" " (apply #'format nil internal-fmt args
)))))
696 (defmethod inspected-description ((object double-float
))
697 (let ((start (round (* 2 sb-vm
::n-word-bits
) 8)))
698 (description-maybe-internals "double-float ~W" (list object
)
700 (ref32-hexstr object
(+ start
4))
701 (ref32-hexstr object start
))))
703 (defmethod inspected-description ((object single-float
))
704 (ecase sb-vm
::n-word-bits
706 (description-maybe-internals "single-float ~W" (list object
)
708 (ref32-hexstr object
(round sb-vm
::n-word-bits
8))))
710 ;; on 64-bit platform, single-floats are not boxed
711 (description-maybe-internals "single-float ~W" (list object
)
713 (ash (sb-kernel:get-lisp-obj-address object
) -
32)))))
715 (defmethod inspected-description ((object fixnum
))
716 (description-maybe-internals
717 "fixnum ~W" (list object
)
718 (concatenate 'string
"[#x" (n-word-bits-hex-format) "]")
719 (ash object
(1- sb-vm
:n-lowtag-bits
))))
721 (defmethod inspected-description ((object complex
))
722 (format nil
"complex number ~W" object
))
724 (defmethod inspected-description ((object simple-string
))
725 (format nil
"a simple-string (~W) ~W" (length object
) object
))
727 (defun bignum-words (bignum)
728 "Return the number of words in a bignum"
730 (logand (ref32 bignum
) (lognot sb-vm
:widetag-mask
))
731 (- sb-vm
:n-widetag-bits
)))
733 (defun bignum-component-at (bignum offset
)
734 "Return the word at offset"
735 (case sb-vm
::n-word-bits
737 (ref32 bignum
(* 4 (1+ offset
))))
739 (let ((start (* 8 (1+ offset
))))
740 (+ (ref32 bignum start
)
741 (ash (ref32 bignum
(+ 4 start
)) 32))))))
743 (defmethod inspected-description ((object bignum
))
744 (format nil
"bignum ~W with ~D ~A-bit word~P" object
745 (bignum-words object
) sb-vm
::n-word-bits
(bignum-words object
)))
747 (defmethod inspected-description ((object ratio
))
748 (format nil
"ratio ~W" object
))
750 (defmethod inspected-description ((object character
))
751 ;; FIXME: This will need to change as and when we get more characters
752 ;; than just the 256 we have today.
753 (description-maybe-internals
754 "character ~W char-code #x~2,'0X"
755 (list object
(char-code object
))
757 (logior sb-vm
:character-widetag
(ash (char-code object
)
758 sb-vm
:n-widetag-bits
))))
760 (defmethod inspected-description ((object t
))
761 (format nil
"a generic object ~W" object
))
763 (defmethod inspected-description ((object (eql *inspect-unbound-object-marker
*)))
767 ;;; FIXME: Most of this should be refactored to share the code
768 ;;; with the vanilla inspector. Also, we should check what the
769 ;;; Slime inspector does, and provide a an interface for it to
770 ;;; use that would propagate any SBCL inspector improvements
771 ;;; automagically to Slime. -- ns 2005-02-20
772 (defgeneric inspected-parts
(object))
774 (defmethod inspected-parts ((object symbol
))
776 (list (cons "NAME" (symbol-name object
))
777 (cons "PACKAGE" (symbol-package object
))
778 (cons "VALUE" (if (boundp object
)
779 (symbol-value object
)
780 *inspect-unbound-object-marker
*))
781 (cons "FUNCTION" (if (fboundp object
)
782 (symbol-function object
)
783 *inspect-unbound-object-marker
*))
784 (cons "PLIST" (symbol-plist object
)))))
785 (list components
(length components
) :named nil
)))
787 (defun inspected-structure-parts (object)
788 (let ((components-list '())
789 (info (sb-kernel:layout-info
(sb-kernel:layout-of object
))))
790 (when (sb-kernel::defstruct-description-p info
)
791 (dolist (dd-slot (sb-kernel:dd-slots info
) (nreverse components-list
))
792 (push (cons (string (sb-kernel:dsd-name dd-slot
))
793 (funcall (sb-kernel:dsd-accessor-name dd-slot
) object
))
796 (defmethod inspected-parts ((object structure-object
))
797 (let ((components (inspected-structure-parts object
)))
798 (list components
(length components
) :named nil
)))
800 (defun inspected-standard-object-parts (object)
801 (let ((components nil
)
802 (class-slots (sb-pcl::class-slots
(class-of object
))))
803 (dolist (class-slot class-slots
(nreverse components
))
804 (let* ((slot-name (slot-value class-slot
'sb-pcl
::name
))
805 (slot-value (if (slot-boundp object slot-name
)
806 (slot-value object slot-name
)
807 *inspect-unbound-object-marker
*)))
808 (push (cons (symbol-name slot-name
) slot-value
) components
)))))
811 (defmethod inspected-parts ((object standard-object
))
812 (let ((components (inspected-standard-object-parts object
)))
813 (list components
(length components
) :named nil
)))
815 (defmethod inspected-parts ((object condition
))
816 (let ((components (inspected-standard-object-parts object
)))
817 (list components
(length components
) :named nil
)))
819 (defmethod inspected-parts ((object function
))
820 (let ((components (list (cons "arglist" (sb-kernel:%fun-lambda-list object
)))))
821 (list components
(length components
) :named nil
)))
823 (defmethod inspected-parts ((object vector
))
824 (list object
(length object
) :vector nil
))
826 (defmethod inspected-parts ((object array
))
827 (let ((size (array-total-size object
)))
828 (list (make-array size
829 :element-type
(array-element-type object
)
830 :displaced-to object
)
833 (reverse (array-dimensions object
)))))
835 (defmethod inspected-parts ((object cons
))
836 (if (simple-cons-pair-p object
)
837 (inspected-parts-of-simple-cons object
)
838 (inspected-parts-of-nontrivial-list object
)))
840 (defun inspected-parts-of-simple-cons (object)
841 (let ((components (list (cons "car" (car object
))
842 (cons "cdr" (cdr object
)))))
843 (list components
2 :named nil
)))
845 (defun inspected-parts-of-nontrivial-list (object)
846 (multiple-value-bind (count list-type
) (cons-safe-length object
)
849 (list object count
:list nil
))
851 (list object
(1+ count
) :cyclic-list nil
))
853 ;; count tail element
854 (list object
(1+ count
) :dotted-list nil
)))))
856 (defmethod inspected-parts ((object complex
))
857 (let ((components (list (cons "real" (realpart object
))
858 (cons "imag" (imagpart object
)))))
859 (list components
(length components
) :named nil
)))
861 (defmethod inspected-parts ((object ratio
))
862 (let ((components (list (cons "numerator" (numerator object
))
863 (cons "denominator" (denominator object
)))))
864 (list components
(length components
) :named nil
)))
866 (defmethod inspected-parts ((object bignum
))
867 (list object
(bignum-words object
) :bignum nil
))
869 (defmethod inspected-parts ((object t
))
870 (list nil
0 nil nil
))
873 ;; FIXME - implement setting of component values
875 (defgeneric set-component-value
(object component-id value element
))
877 (defmethod set-component-value ((object cons
) id value element
)
878 (format nil
"Cons object does not support setting of component ~A" id
))
880 (defmethod set-component-value ((object array
) id value element
)
881 (format nil
"Array object does not support setting of component ~A" id
))
883 (defmethod set-component-value ((object symbol
) id value element
)
884 (format nil
"Symbol object does not support setting of component ~A" id
))
886 (defmethod set-component-value ((object structure-object
) id value element
)
887 (format nil
"Structure object does not support setting of component ~A" id
))
889 (defmethod set-component-value ((object standard-object
) id value element
)
890 (format nil
"Standard object does not support setting of component ~A" id
))
892 (defmethod set-component-value ((object t
) id value element
)
893 (format nil
"Object does not support setting of component ~A" id
))