[slime-devel] inspect, eval-in-frame, inspect-in-frame for openmcl

Alan Ruttenberg alanralanr at comcast.net
Sun Dec 14 07:53:54 UTC 2003


Most of this is copied from swank-cmucl. The parts between &&&&& are 
what I added for openmcl. I piggyback off the inspector which is 
shipped with openmcl, so inspecting won't look the same as it would in 
cmucl, I imagine. Still, it's a start.
eval in frame uses frame-locals to get bindings so if you have debug 
settings low or don't have *save-local-symbols* set you won't be able 
to evaluate.

-Alan

(in-package :swank)

;;;; Inspecting

(defvar *inspectee*)
(defvar *inspectee-parts*)
(defvar *inspector-stack* '())
(defvar *inspector-history* (make-array 10 :adjustable t :fill-pointer 
0))
(defvar *inspect-length* 30)

(defun reset-inspector ()
   (setq *inspectee* nil)
   (setq *inspectee-parts* nil)
   (setq *inspector-stack* nil)
   (setf (fill-pointer *inspector-history*) 0))

(defslimefun init-inspector (string)
   (reset-inspector)
   (inspect-object (eval (from-string string))))

(defun print-part-to-string (value)
   (let ((*print-pretty* nil))
     (let ((string (to-string value))
	  (pos (position value *inspector-history*)))
       (if pos
	  (format nil "#~D=~A" pos string)
	  string))))

(defun inspect-object (object)
   (push (setq *inspectee* object) *inspector-stack*)
   (unless (find object *inspector-history*)
     (vector-push-extend object *inspector-history*))
   (multiple-value-bind (text parts) (inspected-parts object)
     (setq *inspectee-parts* parts)
       (list :text text
	    :type (to-string (type-of object))
	    :primitive-type (describe-primitive-type object)
	    :parts (loop for (label . value) in parts
			 collect (cons label
				       (print-part-to-string value))))))

(defun nth-part (index)
   (cdr (nth index *inspectee-parts*)))

(defslimefun inspect-nth-part (index)
   (inspect-object (nth-part index)))

(defslimefun inspector-pop ()
   "Drop the inspector stack and inspect the second element.  Return
nil if there's no second element."
   (cond ((cdr *inspector-stack*)
	 (pop *inspector-stack*)
	 (inspect-object (pop *inspector-stack*)))
	(t nil)))

(defslimefun inspector-next ()
   "Inspect the next element in the *inspector-history*."
   (let ((position (position *inspectee* *inspector-history*)))
     (cond ((= (1+ position) (length *inspector-history*))
	   nil)
	  (t (inspect-object (aref *inspector-history* (1+ position)))))))

(defslimefun quit-inspector ()
   (reset-inspector)
   nil)

(defslimefun describe-inspectee ()
   "Describe the currently inspected object."
   (print-description-to-string *inspectee*))

(defgeneric inspected-parts (object)
   (:documentation
    "Return a short description and a list of (label . value) pairs."))

;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; specific to openmcl

(defvar *value2tag* (make-hash-table))

(do-symbols (s (find-package 'arch))
   (if (and (> (length (symbol-name s)) 7)
	   (string= (symbol-name s) "SUBTAG-" :end1 7)
	   (boundp s)
	   (numberp (symbol-value s))
	   (< (symbol-value s) 255))
       (setf (gethash (symbol-value s) *value2tag*) s)))

(defun describe-primitive-type (thing)
   (let ((typecode (ccl::typecode thing)))
     (if (gethash typecode *value2tag*)
	(string (gethash typecode *value2tag*))
	(string (nth typecode '(tag-fixnum tag-list tag-misc tag-imm))))))

(defmethod inspected-parts (o)
   (let* ((i (inspector::make-inspector o))
	 (count (inspector::compute-line-count i))
	 (lines (loop for l below count
		      for (value label) = (multiple-value-list (inspector::line-n i 
l))
		      collect
		      (cons
		       (string-right-trim " :" (string-capitalize (format nil "~a"  
label)))
		       value))))
     (values (string-left-trim
	     (string #\newline)
	     (with-output-to-string (s)
	       (let ((*print-lines* 1)
		     (*print-right-margin* 80))
		 (pprint o s))))
	    (cddr lines))))

(defslimefun eval-in-frame (form index)
     (map-backtrace
      #'(lambda (frame-number p tcr lfun pc)
	 (when (= frame-number index)
	   (multiple-value-bind (count vsp parent-vsp)
	       (ccl::count-values-in-frame p tcr)
	     (let ((bindings nil))
	       (dotimes (i count)
		 (multiple-value-bind (var type name)
		     (ccl::nth-value-in-frame p i tcr lfun pc vsp parent-vsp)
		   (declare (ignore type))
		   (when name
		     (push (list name `',var) bindings))
		   ))
	       (return-from eval-in-frame
		 (eval `(let ,bindings
			 (Declare (ccl::ignore-if-unused ,@(mapcar 'car bindings)))
			 ,form)))
	       ))))))

(defslimefun inspect-in-frame (string index)
   (reset-inspector)
   (inspect-object (eval-in-frame (from-string string) index)))
	
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

(defmethod inspected-parts ((object cons))
   (if (consp (cdr object))
       (inspected-parts-of-nontrivial-list object)
       (inspected-parts-of-simple-cons object)))

(defun inspected-parts-of-simple-cons (object)
   (values "The object is a CONS."
	  (list (cons (string 'car) (car object))
		(cons (string 'cdr) (cdr object)))))

(defun inspected-parts-of-nontrivial-list (object)
   (let ((length 0)
	(in-list object)
	(reversed-elements nil))
     (flet ((done (description-format)
	     (return-from inspected-parts-of-nontrivial-list
	       (values (format nil description-format length)
		       (nreverse reversed-elements)))))
       (loop
        (cond ((null in-list)
	      (done "The object is a proper list of length ~S.~%"))
	     ((>= length *inspect-length*)
	      (push (cons  (string 'rest) in-list) reversed-elements)
	      (done "The object is a long list (more than ~S elements).~%"))
	     ((consp in-list)
	      (push (cons (format nil "~D" length) (pop in-list))
		    reversed-elements)
	      (incf length))
	     (t
	      (push (cons (string 'rest) in-list) reversed-elements)
	      (done "The object is an improper list of length ~S.~%")))))))





More information about the slime-devel mailing list