0.pre8.70
[sbcl/simd.git] / contrib / sb-aclrepl / inspect.lisp
blob05ba8d702d517cd093218f77634b6be163ba881f
1 ;;;; Inspector for sb-aclrepl
2 ;;;;
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>.
6 ;;;;
7 ;;;; A summary of inspector navigation is contained in the below *INSPECT-HELP*
8 ;;;; variable.
10 (cl:in-package :sb-aclrepl)
12 (eval-when (:compile-toplevel :load-toplevel :execute)
13 (defconstant +default-inspect-length+ 10))
15 (defstruct inspect
16 ;; stack of parents of inspected object
17 object-stack
18 ;; a stack of indices of parent object components
19 select-stack)
21 ;; FIXME - raw mode isn't currently used in object display
22 (defparameter *current-inspect* nil
23 "current inspect")
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 *inspect-skip* 0
29 "number of initial components to skip when displaying an object")
31 (defvar *inspect-help*
32 ":istep takes between 0 to 3 arguments.
33 The commands are:
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 <index> inspect the numbered component of object
41 :i <name> inspect the named component of object
42 :i <form> evaluation and inspect form
43 :i - inspect parent
44 :i ^ inspect parent
45 :i < inspect previous parent component
46 :i > inspect next parent component
47 :i set <index> <form> set indexed component to evalated form
48 i set <name> <form> set named 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 (defvar *inspect-unbound-object-marker* (gensym "INSPECT-UNBOUND-OBJECT-"))
59 ;; Setup binding for multithreading
60 (let ((*current-inspect* nil)
61 (*inspect-raw* nil)
62 (*inspect-length* +default-inspect-length+)
63 (*inspect-skip* 0))
65 (defun inspector (object input-stream output-stream)
66 (declare (ignore input-stream))
67 (setq object (eval object))
68 (setq *current-inspect* (make-inspect))
69 (new-break :inspect *current-inspect*)
70 (reset-stack)
71 (setf (inspect-object-stack *current-inspect*) (list object))
72 (setf (inspect-select-stack *current-inspect*)
73 (list (format nil "(inspect ~S)" object)))
74 (%inspect output-stream))
77 (defun set-current-inspect (inspect)
78 (setq *current-inspect* inspect))
80 (defun istep (arg-string output-stream)
81 (%istep arg-string output-stream))
83 (setq sb-impl::*inspect-fun* #'inspector)
85 (defun reset-stack ()
86 (setf (inspect-object-stack *current-inspect*) nil)
87 (setf (inspect-select-stack *current-inspect*) nil))
89 (defun %istep (arg-string output-stream)
90 (unless *current-inspect*
91 (setq *current-inspect* (make-inspect)))
92 (let* ((args (when arg-string (string-to-list-skip-spaces arg-string)))
93 (option (car args))
94 (option-read (when arg-string
95 (read-from-string arg-string)))
96 (stack (inspect-object-stack *current-inspect*)))
97 (cond
98 ;; Redisplay
99 ((or (string= "=" option)
100 (zerop (length args)))
101 (%inspect output-stream))
102 ;; Select parent
103 ((or (string= "-" option)
104 (string= "^" option))
105 (cond
106 ((> (length stack) 1)
107 (setf (inspect-object-stack *current-inspect*) (cdr stack))
108 (setf (inspect-select-stack *current-inspect*)
109 (cdr (inspect-select-stack *current-inspect*)))
110 (%inspect output-stream))
111 (stack
112 (format output-stream "Object has no parent.~%"))
114 (%inspect output-stream))))
115 ;; Select * to inspect
116 ((string= "*" option)
117 (reset-stack)
118 (setf (inspect-object-stack *current-inspect*) (list *))
119 (setf (inspect-select-stack *current-inspect*) (list "(inspect *)"))
120 (set-break-inspect *current-inspect*)
121 (%inspect output-stream))
122 ;; Start new inspect level for eval'd form
123 ((string= "+" option)
124 (inspector (eval (read-from-string (second args))) nil output-stream))
125 ;; Next or previous parent component
126 ((or (string= "<" option)
127 (string= ">" option))
128 (if stack
129 (if (eq (length stack) 1)
130 (format output-stream "Object does not have a parent")
131 (let ((parent (second stack))
132 (id (car (inspect-select-stack *current-inspect*))))
133 (multiple-value-bind (position parts)
134 (find-object-part-with-id parent id)
135 (let ((new-position (if (string= ">" option)
136 (1+ position)
137 (1- position))))
138 (if (< -1 new-position (parts-count parts))
139 (let* ((value (element-at parts new-position)))
140 (setf (car stack) value)
141 (setf (car (inspect-select-stack *current-inspect*))
142 (if (integerp id)
143 new-position
144 (let ((label (label-at parts new-position)))
145 (if (stringp label)
146 (read-from-string label)
147 label))))
148 (%inspect output-stream))
149 (format output-stream "Parent has no selectable component indexed by ~d"
150 new-position))))))
151 (%inspect output-stream)))
152 ;; Set component to eval'd form
153 ((string-equal "set" option)
154 (if stack
155 (let ((id (when (second args)
156 (read-from-string (second args)))))
157 (multiple-value-bind (position parts)
158 (find-object-part-with-id (car stack) id)
159 (if parts
160 (if position
161 (let ((value-stirng (third args)))
162 (when value-stirng
163 (let ((new-value (eval (read-from-string (third args)))))
164 (let ((result
165 (set-component-value (car stack)
167 new-value
168 (element-at parts position))))
169 (typecase result
170 (string
171 (format output-stream result))
173 (%inspect output-stream)))))))
174 (format output-stream
175 "Object has no selectable component named by ~A" id))
176 (format output-stream
177 "Object has no selectable components"))))
178 (%inspect output-stream)))
179 ;; Set/reset raw display mode for components
180 ((string-equal "raw" option)
181 (when stack
182 (when (and (second args)
183 (or (null (second args))
184 (eq (read-from-string (second args)) t)))
185 (setq *inspect-raw* t))
186 (%inspect output-stream)))
187 ;; Reset stack
188 ((string-equal "q" option)
189 (reset-stack)
190 (set-break-inspect *current-inspect*))
191 ;; Display help
192 ((string-equal "?" option)
193 (format output-stream *inspect-help*))
194 ;; Set number of components to skip
195 ((string-equal "skip" option)
196 (let ((len (read-from-string (second args))))
197 (if (and (integerp len) (>= len 0))
198 (let ((*inspect-skip* len))
199 (%inspect output-stream))
200 (format output-stream "Skip missing or invalid~%"))))
201 ;; Print stack tree
202 ((string-equal "tree" option)
203 (if stack
204 (progn
205 (format output-stream "The current object is:~%")
206 (dotimes (i (length stack))
207 (format output-stream "~A, ~A~%"
208 (inspected-description (nth i stack))
209 (let ((select (nth i (inspect-select-stack *current-inspect*))))
210 (typecase select
211 (integer
212 (format nil "which is componenent number ~d of" select))
213 (symbol
214 (format nil "which is the ~a component of" select))
215 (string
216 (format nil "which was selected by ~S" select))
218 (write-to-string select)))))))
219 (%inspect output-stream)))
220 ;; Set maximum number of components to print
221 ((string-equal "print" option)
222 (let ((len (read-from-string (second args))))
223 (if (and (integerp len) (plusp len))
224 (setq *inspect-length* len)
225 (format output-stream "Cannot set print limit to ~A~%" len))))
226 ;; Select numbered or named component
227 ((or (symbolp option-read)
228 (integerp option-read))
229 (if stack
230 (multiple-value-bind (position parts)
231 (find-object-part-with-id (car stack) option-read)
232 (cond
233 ((integerp position)
234 (let* ((value (element-at parts position)))
235 (cond ((eq value *inspect-unbound-object-marker*)
236 (format output-stream "That slot is unbound~%"))
238 (push value (inspect-object-stack *current-inspect*))
239 (push option-read (inspect-select-stack *current-inspect*))
240 (%inspect output-stream)))))
241 ((null parts)
242 (format output-stream "Object does not contain any subobjects~%"))
244 (typecase option-read
245 (symbol
246 (format output-stream
247 "Object has no selectable component named ~A"
248 option))
249 (integer
250 (format output-stream
251 "Object has no selectable component indexed by ~d~&Enter a valid index (~:[0-~W~;0~])~%"
252 option-read
253 (= (parts-count parts) 1)
254 (1- (parts-count parts))))))))
255 (%inspect output-stream)))
256 ;; Default is to select eval'd form
258 (reset-stack)
259 (let ((object (eval option-read)))
260 (setf (inspect-object-stack *current-inspect*) (list object))
261 (setf (inspect-select-stack *current-inspect*)
262 (list (format nil ":i ~S" object))))
263 (set-break-inspect *current-inspect*)
264 (%inspect output-stream))
267 (defun %inspect (s)
268 (if (inspect-object-stack *current-inspect*)
269 (let ((inspected (car (inspect-object-stack *current-inspect*))))
270 (setq cl:* inspected)
271 (display-inspected-parts inspected s))
272 (format s "No object is being inspected")))
275 (defun display-inspected-parts (object stream)
276 (multiple-value-bind (elements labels count)
277 (inspected-elements object *inspect-length* *inspect-skip*)
278 (format stream "~&~A" (inspected-description object))
279 (unless (or (characterp object) (typep object 'fixnum))
280 (format stream " at #x~X" (sb-kernel:get-lisp-obj-address object)))
281 (princ #\newline stream)
282 (dotimes (i count)
283 (let ((label (elt labels i))
284 (element (elt elements i)))
285 (cond
286 ((eq label :ellipses)
287 (format stream "~& ...~%"))
288 ((eq label :tail)
289 (format stream "tail-> ~A~%" (inspected-description element)))
290 ((consp label)
291 (format stream
292 (if (and (stringp (cdr label)) (char= (char (cdr label) 0) #\[))
293 ;; for arrays
294 "~4,' D ~A-> ~A~%"
295 ;; for named
296 "~4,' D ~16,1,1,'-A> ~A~%")
297 (car label)
298 (format nil "~A " (cdr label))
299 (if (eq element *inspect-unbound-object-marker*)
300 "..unbound.."
301 (inspected-description element))))
303 (if (integerp label)
304 (format stream "~4,' D-> ~A~%" label (inspected-description element))
305 (format stream "~4A-> ~A~%" label (inspected-description element)))))))))
307 ) ;; end binding for multithreading
310 ;;; THE BEGINNINGS OF AN INSPECTOR API
311 ;;; which can be used to retrieve object descriptions as component values/labels and also
312 ;;; process component length and skip selectors
314 ;;; FUNCTIONS TO CONSIDER FOR EXPORT
315 ;;; FIND-OBJECT-PART-WITH-ID
316 ;;; ELEMENT-AT
317 ;;; LABEL-AT
318 ;;; INSPECTED-ELEMENTS
319 ;;; INSPECTED-DESCRIPTION
321 ;;; will also need hooks
322 ;;; *inspect-start-inspection* (maybe. Would setup a window for a GUI inspector)
323 ;;; *inspect-prompt-fun*
324 ;;; *inspect-read-cmd*
326 ;;; and, either an *inspect-process-cmd*, or *inspect-display* hook
327 ;;; That'll depend if choose to have standardized inspector commands such that
328 ;;; (funcall *inspect-read-cmd*) will return a standard command that SBCL will
329 ;;; process and then call the *inspect-display* hook, or if the *inspect-read-cmd*
330 ;;; will return an impl-dependent cmd that sbcl will send to the contributed
331 ;;; inspector for processing and display.
333 (defun find-object-part-with-id (object id)
334 "COMPONENT-ID can be an integer or a name of a id.
335 Returns (VALUES POSITION PARTS).
336 POSITION is NIL if the id is invalid or not found."
337 (if object
338 (let* ((parts (inspected-parts object))
339 (seq-type (parts-seq-type parts))
340 (count (parts-count parts))
341 (components (parts-components parts)))
342 (when (symbolp id)
343 (setq id (symbol-name id)))
344 (let ((position
345 (cond ((and (eq seq-type :named)
346 (stringp id))
347 (position id (the list components) :key #'car
348 :test #'string-equal))
349 ((and (eq seq-type :improper-list)
350 (stringp id)
351 (string-equal id "tail"))
352 (1- count))
353 ((numberp id)
354 (when (< -1 id count)
355 id)))))
356 (values position parts)))
357 (values nil nil)))
360 (defun element-at (parts position)
361 (let ((count (parts-count parts))
362 (components (parts-components parts)))
363 (when (< -1 position count)
364 (case (parts-seq-type parts)
365 (:improper-list
366 (if (= position (1- count))
367 (cdr (last components))
368 (elt components position)))
369 (:named
370 (cdr (elt components position)))
371 (:array
372 (aref (the array components) position))
374 (elt components position))))))
376 (defun label-at (parts position)
377 (let ((count (parts-count parts)))
378 (when (< -1 position count)
379 (case (parts-seq-type parts)
380 (:improper-list
381 (if (= position (1- count))
382 :tail
383 position))
384 (:array
385 (array-index-string position parts))
386 (:named
387 (car (elt (parts-components parts) position)))
389 position)))))
391 (defun label-at-maybe-with-index (parts position)
392 "Helper function for inspected-elements. Conses the
393 position with the label is the label is a string."
394 (let ((label (label-at parts position)))
395 (if (or (stringp label)
396 (and (symbolp label) (not (eq label :tail))))
397 (cons position label)
398 label)))
400 (defun array-index-string (index parts)
401 "Formats an array index in row major format."
402 (let ((rev-dimensions (parts-seq-hint parts)))
403 (if (null rev-dimensions)
404 "[]"
405 (let ((list nil))
406 (dolist (dim rev-dimensions)
407 (multiple-value-bind (q r) (floor index dim)
408 (setq index q)
409 (push r list)))
410 (format nil "[~W~{,~W~}]" (car list) (cdr list))))))
412 (defun inspected-elements (object length skip)
413 "Returns elements of an object that have been trimmed and labeled based on
414 length and skip. Returns (VALUES ELEMENTS LABELS COUNT) where ELEMENTS contains
415 COUNT ITERMS, LABELS is a SEQUENCES with COUNT items. LABELS may be a string, number,
416 :tail, or :ellipses. This function may return a COUNT of up to (+ 3 length) which would
417 include an :ellipses at the beginning, :ellipses at the end, and the last element."
418 (let* ((parts (inspected-parts object))
419 (count (parts-count parts)))
420 (unless skip (setq skip 0))
421 (unless length (setq length count))
422 (let* ((last (1- count))
423 (last-req (min last (+ skip length -1))) ;; last requested element
424 (total (min (- count skip) length)))
425 (when (and (plusp total) (plusp skip)) ; starting ellipses
426 (incf total))
427 (when (< last-req last) ; last value
428 (incf total)
429 (when (< last-req (1- last)) ; ending ellipses
430 (incf total)))
431 (let ((index 0)
432 (elements nil)
433 (labels nil))
434 (declare (type (or simple-vector null) elements labels))
435 (when (plusp total)
436 (setq elements (make-array total :adjustable nil :fill-pointer nil :initial-element nil))
437 (setq labels (make-array total :adjustable nil :fill-pointer nil))
438 (when (plusp skip)
439 (setf (aref labels 0) :ellipses)
440 (incf index))
441 (do ((i 0 (1+ i)))
442 ((> i (- last-req skip)))
443 (setf (aref elements (+ i index)) (element-at parts (+ i skip)))
444 (setf (aref labels (+ i index)) (label-at-maybe-with-index parts
445 (+ i skip))))
447 (when (< last-req last) ; last value
448 (setf (aref elements (- total 1)) (element-at parts last))
449 (setf (aref labels (- total 1)) (label-at-maybe-with-index parts
450 last))
451 (when (< last-req (1- last)) ; ending ellipses or 2nd to last value
452 (if (= last-req (- last 2))
453 (progn
454 (setf (aref elements (- total 2)) (element-at parts (1- last)))
455 (setf (aref labels (- total 2)) (label-at-maybe-with-index
456 parts (1- last))))
457 (setf (aref labels (- total 2)) :ellipses)))))
458 (values elements labels total)))))
462 ;;; INSPECTED-DESCRIPTION
464 ;;; Accepts an object and returns
465 ;;; DESCRIPTION is a summary description of the destructured object,
466 ;;; e.g. "the object is a CONS".
468 (defgeneric inspected-description (object))
470 (defmethod inspected-description ((object symbol))
471 (format nil "the symbol ~A" object))
473 (defmethod inspected-description ((object structure-object))
474 (format nil "~W" (find-class (type-of object))))
476 (defmethod inspected-description ((object package))
477 (format nil "the ~A package" (package-name object)))
479 (defmethod inspected-description ((object standard-object))
480 (format nil "~W" (class-of object)))
482 (defmethod inspected-description ((object sb-kernel:funcallable-instance))
483 (format nil "a funcallable-instance of type ~S" (type-of object)))
485 (defmethod inspected-description ((object function))
486 (format nil "~S" object) nil)
488 (defmethod inspected-description ((object vector))
489 (declare (vector object))
490 (format nil "a ~:[~;displaced ~]vector (~W)"
491 (and (sb-kernel:array-header-p object)
492 (sb-kernel:%array-displaced-p object))
493 (length object)))
495 (defmethod inspected-description ((object simple-vector))
496 (declare (simple-vector object))
497 (format nil "a simple ~A vector (~D)"
498 (array-element-type object)
499 (length object)))
501 (defmethod inspected-description ((object array))
502 (declare (array object))
503 (format nil "~:[A displaced~;An~] array of ~A with dimensions ~W"
504 (and (sb-kernel:array-header-p object)
505 (sb-kernel:%array-displaced-p object))
506 (array-element-type object)
507 (array-dimensions object)))
509 (defun simple-cons-pair-p (object)
510 (atom (cdr object)))
512 (defmethod inspected-description ((object cons))
513 (if (simple-cons-pair-p object)
514 "a cons cell"
515 (inspected-description-of-nontrivial-list object)))
517 (defun dotted-safe-length (object)
518 "Returns (VALUES LENGTH PROPER-P) where length is the number of cons cells"
519 (do ((length 0 (1+ length))
520 (lst object (cdr lst)))
521 ((not (consp lst))
522 (if (null lst)
523 (values length t)
524 (values length nil)))
525 ;; nothing to do in body
528 (defun inspected-description-of-nontrivial-list (object)
529 (multiple-value-bind (length proper-p) (dotted-safe-length object)
530 (if proper-p
531 (format nil "a proper list with ~D element~:*~P" length)
532 (format nil "a dotted list with ~D element~:*~P + tail" length))))
534 (defmethod inspected-description ((object double-float))
535 (format nil "double-float ~W" object))
537 (defmethod inspected-description ((object single-float))
538 (format nil "single-float ~W" object))
540 (defmethod inspected-description ((object fixnum))
541 (format nil "fixnum ~W" object))
543 (defmethod inspected-description ((object complex))
544 (format nil "complex number ~W" object))
546 (defmethod inspected-description ((object simple-string))
547 (format nil "a simple-string (~W) ~W" (length object) object))
549 (defmethod inspected-description ((object bignum))
550 (format nil "bignum ~W" object))
552 (defmethod inspected-description ((object ratio))
553 (format nil "ratio ~W" object))
555 (defmethod inspected-description ((object character))
556 (format nil "character ~W char-code #x~X" object (char-code object)))
558 (defmethod inspected-description ((object t))
559 (format nil "a generic object ~W" object))
562 ;;; INSPECTED-PARTS
564 ;;; Accepts the arguments OBJECT LENGTH SKIP and returns,
565 ;;; (LIST COMPONENTS SEQ-TYPE COUNT SEQ-HINT)
566 ;;; where..
568 ;;; COMPONENTS are the component parts of OBJECT (whose
569 ;;; representation is determined by SEQ-TYPE). Except for the
570 ;;; SEQ-TYPE :named and :array, components is just the OBJECT itself
572 ;;; SEQ-TYPE determines what representation is used for components
573 ;;; of COMPONENTS.
574 ;;; If SEQ-TYPE is :named, then each element is (CONS NAME VALUE)
575 ;;; If SEQ-TYPE is :improper-list, then each element is just value,
576 ;;; but the last element must be retrieved by
577 ;;; (cdr (last components))
578 ;;; If SEQ-TYPE is :list, then each element is a value of an array
579 ;;; If SEQ-TYPE is :vector, then each element is a value of an vector
580 ;;; If SEQ-TYPE is :array, then each element is a value of an array
581 ;;; with rank >= 2
583 ;;; COUNT is the total number of components in the OBJECT
585 ;;; SEQ-HINT Stores a seq-type dependent hint. Used by SEQ-TYPE :array
586 ;;; to hold the reverse-dimensions of the orignal array.
588 (declaim (inline parts-components))
589 (defun parts-components (parts)
590 (first parts))
592 (declaim (inline parts-count))
593 (defun parts-count (parts)
594 (second parts))
596 (declaim (inline parts-seq-type))
597 (defun parts-seq-type (parts)
598 (third parts))
600 (declaim (inline parts-seq-hint))
601 (defun parts-seq-hint (parts)
602 (fourth parts))
604 (defgeneric inspected-parts (object)
607 (defmethod inspected-parts ((object symbol))
608 (let ((components
609 (list (cons "name" (symbol-name object))
610 (cons "package" (symbol-package object))
611 (cons "value" (if (boundp object)
612 (symbol-value object)
613 *inspect-unbound-object-marker*))
614 (cons "function" (if (fboundp object)
615 (symbol-function object)
616 *inspect-unbound-object-marker*))
617 (cons "plist" (symbol-plist object)))))
618 (list components (length components) :named nil)))
620 (defun inspected-structure-parts (object)
621 (let ((components-list '())
622 (info (sb-kernel:layout-info (sb-kernel:layout-of object))))
623 (when (sb-kernel::defstruct-description-p info)
624 (dolist (dd-slot (sb-kernel:dd-slots info) (nreverse components-list))
625 (push (cons (sb-kernel:dsd-%name dd-slot)
626 (funcall (sb-kernel:dsd-accessor-name dd-slot) object))
627 components-list)))))
629 (defmethod inspected-parts ((object structure-object))
630 (let ((components (inspected-structure-parts object)))
631 (list components (length components) :named nil)))
633 (defun inspected-standard-object-parts (object)
634 (let ((reversed-components nil)
635 (class-slots (sb-pcl::class-slots (class-of object))))
636 (dolist (class-slot class-slots (nreverse reversed-components))
637 (let* ((slot-name (slot-value class-slot 'sb-pcl::name))
638 (slot-value (if (slot-boundp object slot-name)
639 (slot-value object slot-name)
640 *inspect-unbound-object-marker*)))
641 (push (cons slot-name slot-value) reversed-components)))))
643 (defmethod inspected-parts ((object standard-object))
644 (let ((components (inspected-standard-object-parts object)))
645 (list components (length components) :named nil)))
647 (defmethod inspected-parts ((object sb-kernel:funcallable-instance))
648 (let ((components (inspected-structure-parts object)))
649 (list components (length components) :named nil)))
651 (defmethod inspected-parts ((object function))
652 (let* ((type (sb-kernel:widetag-of object))
653 (object (if (= type sb-vm:closure-header-widetag)
654 (sb-kernel:%closure-fun object)
655 object))
656 (components (list (cons "arglist"
657 (sb-kernel:%simple-fun-arglist object)))))
658 (list components (length components) :named nil)))
660 (defmethod inspected-parts ((object vector))
661 (list object (length object) :vector nil))
663 (defmethod inspected-parts ((object array))
664 (let ((size (array-total-size object)))
665 (list (make-array size :displaced-to object)
666 size
667 :array
668 (reverse (array-dimensions object)))))
670 (defmethod inspected-parts ((object cons))
671 (if (simple-cons-pair-p object)
672 (inspected-parts-of-simple-cons object)
673 (inspected-parts-of-nontrivial-list object)))
675 (defun inspected-parts-of-simple-cons (object)
676 (let ((components (list (cons "car" (car object))
677 (cons "cdr" (cdr object)))))
678 (list components 2 :named nil)))
680 (defun inspected-parts-of-nontrivial-list (object)
681 (multiple-value-bind (count proper-p) (dotted-safe-length object)
682 (if proper-p
683 (list object count :list nil)
684 ;; count tail element
685 (list object (1+ count) :improper-list nil))))
687 (defmethod inspected-parts ((object complex))
688 (let ((components (list (cons "real" (realpart object))
689 (cons "imag" (imagpart object)))))
690 (list components (length components) :named nil)))
692 (defmethod inspected-parts ((object ratio))
693 (let ((components (list (cons "numerator" (numerator object))
694 (cons "denominator" (denominator object)))))
695 (list components (length components) :named nil)))
697 (defmethod inspected-parts ((object t))
698 (list nil 0 nil nil))
701 ;; FIXME - implement setting of component values
703 (defgeneric set-component-value (object component-id value element))
705 (defmethod set-component-value ((object cons) id value element)
706 (format nil "Cons object does not support setting of component ~A" id))
708 (defmethod set-component-value ((object array) id value element)
709 (format nil "Array object does not support setting of component ~A" id))
711 (defmethod set-component-value ((object symbol) id value element)
712 (format nil "Symbol object does not support setting of component ~A" id))
714 (defmethod set-component-value ((object structure-object) id value element)
715 (format nil "Structure object does not support setting of component ~A" id))
717 (defmethod set-component-value ((object standard-object) id value element)
718 (format nil "Standard object does not support setting of component ~A" id))
720 (defmethod set-component-value ((object sb-kernel:funcallable-instance) id value element)
721 (format nil "Funcallable instance object does not support setting of component ~A" id))
723 (defmethod set-component-value ((object function) id value element)
724 (format nil "Function object does not support setting of component ~A" id))
726 ;; whn believes it is unsafe to change components of this object
727 (defmethod set-component-value ((object complex) id value element)
728 (format nil "Object does not support setting of component ~A" id))
730 ;; whn believes it is unsafe to change components of this object
731 (defmethod set-component-value ((object ratio) id value element)
732 (format nil "Object does not support setting of component ~A" id))
734 (defmethod set-component-value ((object t) id value element)
735 (format nil "Object does not support setting of component ~A" id))