emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] externals/sly 57b6d3f 18/47: abcl: consolidate fixes and featur


From: ELPA Syncer
Subject: [nongnu] externals/sly 57b6d3f 18/47: abcl: consolidate fixes and features
Date: Thu, 17 Dec 2020 18:57:16 -0500 (EST)

branch: externals/sly
commit 57b6d3fd2d4634313cd23c83a3fbd7fa53ad55a4
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>

    abcl: consolidate fixes and features
    
    (Alan Ruttenberg)(Mark Evenson)
    
         SLY Author João Távora: This rather chubby mega-commit appeared
         like this in SLIME.  Git did its best when cherry-picking and so
         did I when renaming.  Seems ABCL has some slime-specific symbols,
         like EXT:MAKE-SLIME-OUTPUT-STREAM, and I kept those.  But others
         may have crept by.  Untested.
    
    Consolidated fixes and features to working across the most common ABCL
    releases, namely development (1.6.0-dev), current (1.5.0) and
    historical (1.4.0).  A majority of the new features depend on the
    ABCL-INTROSPECT tooling introduced with abcl-1.5.0, to which we
    intend to conditionalize their use on a backwards compatible strategy.
    
    From 
<https://github.com/slime/slime/pull/477/commits/c7c72d7b0f5cd6473af3488202ea1eca24d58202>.
    
    Enable goto source location to find definitions in JAR archives.
    
    For primitives compiled from Java source, return implementation source
    location designated by the logical pathname associated with 'SYS:SRC'.
    
    Finding functions and methods works well, other than when methods are
    defined as part of a DEFGENERIC form, or implicitly as with :report on
    condition defining PRINT-OBJECT.
    
    FIND-DEFINITIONS include symbols and specials defined in Java.
    
    Redirect source lookup to system jar if it's not where it claims to be.
    
    Show stack trace when inspecting Java conditions.
    
    Implement an inspector for Java classes.
    
    Print internal variables in Java stack traces.
    
    Prettier function name if we can glean information about otherwise
    anonymous function.
    
    Fix so that edit slot action in CLOS object inspector works.
    
    Don't use the ABCL native printObject() for frames, so we can get prettier
    function display.
    
    Compile DEFIMPLEMENTATION forms so that they are visible to edit definition.
    
    Fix source-location (used by view frame source) to work in general and
    in particular for local function - go to the source of their owner.
    
    Don't show bogus locals for Java stack frames.
    
    Enables load of xref package.
    
    Only add ABCL-INTROSPECT once to *FEATURES*.
    
    Robustly find intended class of Java objects.
    
    Tweak to invoke hyperspec in inspector (offered in symbol browser if a
    CL symbol) - *SLIME-INSPECTOR-HYPERSPEC-IN-BROWSER* if t shows
    hyperspec in emacs buffer despite setting of
    browse-url-browser-function.  This should eventually be moved into
    more generalized Swank facilities if useful to others.
    
    Co-authored-by: João Távora <joaotavora@gmail.com>
    Cherry-pick-from: SLIME commit 6f06402595df0ec6b305fc5a13e18f48e8989c64
---
 slynk/backend/abcl.lisp | 1247 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 971 insertions(+), 276 deletions(-)

diff --git a/slynk/backend/abcl.lisp b/slynk/backend/abcl.lisp
index 7fbd34c..aedaaa6 100644
--- a/slynk/backend/abcl.lisp
+++ b/slynk/backend/abcl.lisp
@@ -3,29 +3,56 @@
 ;;; slynk-abcl.lisp --- Armedbear CL specific code for SLY.
 ;;;
 ;;; Adapted from slynk-acl.lisp, Andras Simon, 2004
+;;; New work by Alan Ruttenberg, 2016-7
 ;;;
 ;;; This code has been placed in the Public Domain.  All warranties
 ;;; are disclaimed.
 ;;;
 
-(defpackage slynk-abcl
-  (:use cl slynk-backend))
-
-(in-package slynk-abcl)
+(defpackage slynk/abcl
+  (:use cl slynk/backend)
+  (:import-from :java
+                #:jcall #:jstatic
+                #:jmethod
+                #:jfield 
+                #:jconstructor
+                #:jnew-array #:jarray-length #:jarray-ref 
#:jnew-array-from-array
+                #:jclass #:jnew #:java-object 
+                ;; be conservative and add any import java functions only for 
later lisps
+                #+#.(slynk/backend:with-symbol 'jfield-name 'java) 
#:jfield-name
+                #+#.(slynk/backend:with-symbol 'jinstance-of-p 'java) 
#:jinstance-of-p
+                #+#.(slynk/backend:with-symbol 'jclass-superclass 'java) 
#:jclass-superclass
+                #+#.(slynk/backend:with-symbol 'jclass-interfaces 'java) 
#:jclass-interfaces
+                #+#.(slynk/backend:with-symbol 'java-exception 'java) 
#:java-exception
+                #+#.(slynk/backend:with-symbol 'jobject-class 'java) 
#:jobject-class
+                #+#.(slynk/backend:with-symbol 'jclass-name 'java) 
#:jclass-name
+                #+#.(slynk/backend:with-symbol 'java-object-p 'java) 
#:java-object-p))
+
+(in-package slynk/abcl)
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
   (require :collect) ;just so that it doesn't spoil the flying letters
   (require :pprint)
   (require :gray-streams)
-  (assert (>= (read-from-string (subseq (lisp-implementation-version) 0 4))
-              0.22)
-          () "This file needs ABCL version 0.22 or newer"))
+  (require :abcl-contrib)
+
+  ;;; Probe and load ABCL-INTROSPECT pushing to *FEATURES* on success
+  ;;; allowing us to conditionalize usage via `#+abcl-introspect` forms.
+  (when (ignore-errors (and
+                        (fboundp '(setf sys::function-plist)) 
+                        (progn
+                          (require :abcl-introspect)
+                          (find "ABCL-INTROSPECT" *modules* :test
+                                'equal))))
+    (pushnew :abcl-introspect *features*)))
 
 (defimplementation gray-package-name ()
   "GRAY-STREAMS")
 
-;; FIXME: switch to shared Gray stream implementation when bugs are
-;; fixed in ABCL.  See: http://abcl.org/trac/ticket/373.
+;; FIXME: switch to shared Gray stream implementation when the
+;; architecture for booting streams allows us to replace the Java-side
+;; implementation of a Sly{Input,Output}Stream.java classes are
+;; subsumed <http://abcl.org/trac/ticket/373>.
 (progn
   (defimplementation make-output-stream (write-string)
     (ext:make-slime-output-stream write-string))
@@ -34,20 +61,56 @@
     (ext:make-slime-input-stream read-string
                                  (make-synonym-stream '*standard-output*))))
 
+;;; Have CL:INSPECT use SLY
+;;;
+;;; Since Slynk may also be run in a server not running under Emacs
+;;; and potentially with other REPLs, we export a functional toggle
+;;; for the user to call after loading these definitions.
+(defun enable-cl-inspect-in-emacs ()
+  (slynk::wrap 'cl:inspect :use-sly :replace 'slynk::inspect-in-emacs))
+
+;; ??? repair bare print object so inspector titles show java class
+(defun %print-unreadable-object-java-too (object stream type identity body)
+  (setf stream (sys::out-synonym-of stream))
+  (when *print-readably*
+    (error 'print-not-readable :object object))
+  (format stream "#<")
+  (when type
+    (if (java-object-p object)
+        ;; Special handling for java objects
+        (if (jinstance-of-p object "java.lang.Class")
+            (progn
+              (write-string "jclass " stream)
+              (format stream "~a" (jclass-name object)))
+            (format stream "~a" (jclass-name (jobject-class object))))
+        ;; usual handling
+        (format stream "~S" (type-of object)))
+      (format stream " "))
+  (when body
+    (funcall body))
+  (when identity
+    (when (or body (not type))
+      (format stream " "))
+    (format stream "{~X}" (sys::identity-hash-code object)))
+  (format stream ">")
+  nil)
+
+(wrap 'sys::%print-unreadable-object :more-informative :replace 
'%print-unreadable-object-java-too)
+
 (defimplementation call-with-compilation-hooks (function)
   (funcall function))
 
-;;; slynk-mop
+
+;;;; MOP
 
 ;;dummies and definition
 
 (defclass standard-slot-definition ()())
 
-;(defun class-finalized-p (class) t)
-
 (defun slot-definition-documentation (slot)
   (declare (ignore slot))
-  #+nil (documentation slot 't))
+  #+abcl-introspect
+  (documentation slot 't))
 
 (defun slot-definition-type (slot)
   (declare (ignore slot))
@@ -84,14 +147,18 @@
   (declare (ignore class))
   (system::slot-value object (slot-definition-name slotdef)))
 
+(defun (setf slot-value-using-class) (new class object slotdef )
+  (declare (ignore class))
+  (mop::%set-slot-value object (slot-definition-name slotdef) new))
+
 (import-to-slynk-mop
  '( ;; classes
    cl:standard-generic-function
    standard-slot-definition ;;dummy
    cl:method
    cl:standard-class
-   #+#.(slynk-backend:with-symbol 'compute-applicable-methods-using-classes 
-         'mop)
+   #+#.(slynk/backend:with-symbol
+           'compute-applicable-methods-using-classes 'mop)
    mop:compute-applicable-methods-using-classes
    ;; standard-class readers
    mop:class-default-initargs
@@ -100,13 +167,13 @@
    mop:class-direct-subclasses
    mop:class-direct-superclasses
    mop:eql-specializer
-   mop:class-finalized-p 
+   mop:class-finalized-p
    mop:finalize-inheritance
    cl:class-name
    mop:class-precedence-list
    class-prototype ;;dummy
    class-slots
-   specializer-direct-methods 
+   specializer-direct-methods
    ;; eql-specializer accessors
    mop::eql-specializer-object
    ;; generic function readers
@@ -135,11 +202,13 @@
    mop:slot-definition-writers
    slot-boundp-using-class
    slot-value-using-class
+   set-slot-value-using-class
+   #+#.(slynk/backend:with-symbol
+           'slot-makunbound-using-class 'mop)
    mop:slot-makunbound-using-class))
 
 ;;;; TCP Server
 
-
 (defimplementation preferred-communication-style ()
   :spawn)
 
@@ -147,33 +216,33 @@
   (ext:make-server-socket port))
 
 (defimplementation local-port (socket)
-  (java:jcall (java:jmethod "java.net.ServerSocket" "getLocalPort") socket))
+  (jcall (jmethod "java.net.ServerSocket" "getLocalPort") socket))
 
 (defimplementation close-socket (socket)
   (ext:server-socket-close socket))
 
-(defimplementation accept-connection (socket 
+(defimplementation accept-connection (socket
                                       &key external-format buffering timeout)
   (declare (ignore buffering timeout))
   (ext:get-socket-stream (ext:socket-accept socket)
-                         :element-type (if external-format 
-                                           'character 
+                         :element-type (if external-format
+                                           'character
                                            '(unsigned-byte 8))
                          :external-format (or external-format :default)))
 
-;;;; UTF8 
+;;;; UTF8
 
 ;; faster please!
 (defimplementation string-to-utf8 (s)
   (jbytes-to-octets
-   (java:jcall 
+   (java:jcall
     (java:jmethod "java.lang.String" "getBytes" "java.lang.String")
     s
     "UTF8")))
 
 (defimplementation utf8-to-string (u)
-  (java:jnew 
-   (java:jconstructor "org.armedbear.lisp.SimpleString" 
+  (java:jnew
+   (java:jconstructor "org.armedbear.lisp.SimpleString"
                       "java.lang.String")
    (java:jnew (java:jconstructor "java.lang.String" "[B" "java.lang.String")
               (octets-to-jbytes u)
@@ -185,8 +254,8 @@
          (bytes (java:jnew-array "byte" len)))
     (loop for byte across octets
           for i from 0
-          do (java:jstatic (java:jmethod "java.lang.reflect.Array"  "setByte" 
-                            "java.lang.Object" "int" "byte")
+          do (java:jstatic (java:jmethod "java.lang.reflect.Array"  "setByte"
+                                         "java.lang.Object" "int" "byte")
                            "java.lang.reflect.Array"
                            bytes i byte))
     bytes))
@@ -203,7 +272,7 @@
 
 (defvar *external-format-to-coding-system*
   '((:iso-8859-1 "latin-1" "iso-latin-1" "iso-8859-1")
-    ((:iso-8859-1 :eol-style :lf) 
+    ((:iso-8859-1 :eol-style :lf)
      "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix")
     (:utf-8 "utf-8")
     ((:utf-8 :eol-style :lf) "utf-8-unix")
@@ -220,37 +289,39 @@
 ;;;; Unix signals
 
 (defimplementation getpid ()
-  (handler-case 
-      (let* ((runtime 
-              (java:jstatic "getRuntime" "java.lang.Runtime"))
-             (command
-              (java:jnew-array-from-array 
-               "java.lang.String" #("sh" "-c" "echo $PPID")))
-             (runtime-exec-jmethod             
-              ;; Complicated because java.lang.Runtime.exec() is
-              ;; overloaded on a non-primitive type (array of
-              ;; java.lang.String), so we have to use the actual
-              ;; parameter instance to get java.lang.Class
-              (java:jmethod "java.lang.Runtime" "exec" 
-                            (java:jcall 
-                             (java:jmethod "java.lang.Object" "getClass")
-                             command)))
-             (process 
-              (java:jcall runtime-exec-jmethod runtime command))
-             (output 
-              (java:jcall (java:jmethod "java.lang.Process" "getInputStream")
-                          process)))
-         (java:jcall (java:jmethod "java.lang.Process" "waitFor")
-                     process)
-        (loop :with b :do 
-           (setq b 
-                 (java:jcall (java:jmethod "java.io.InputStream" "read")
-                             output))
-           :until (member b '(-1 #x0a))        ; Either EOF or LF
-           :collecting (code-char b) :into result
-           :finally (return 
-                      (parse-integer (coerce result 'string)))))
-    (t () 0))) 
+  (if (fboundp 'ext::get-pid)
+      (ext::get-pid)       ;;; Introduced with abcl-1.5.0
+      (handler-case
+          (let* ((runtime
+                  (java:jstatic "getRuntime" "java.lang.Runtime"))
+                 (command
+                  (java:jnew-array-from-array
+                   "java.lang.String" #("sh" "-c" "echo $PPID")))
+                 (runtime-exec-jmethod
+                  ;; Complicated because java.lang.Runtime.exec() is
+                  ;; overloaded on a non-primitive type (array of
+                  ;; java.lang.String), so we have to use the actual
+                  ;; parameter instance to get java.lang.Class
+                  (java:jmethod "java.lang.Runtime" "exec"
+                                (java:jcall
+                                 (java:jmethod "java.lang.Object" "getClass")
+                                 command)))
+                 (process
+                  (java:jcall runtime-exec-jmethod runtime command))
+                 (output
+                  (java:jcall (java:jmethod "java.lang.Process" 
"getInputStream")
+                              process)))
+            (java:jcall (java:jmethod "java.lang.Process" "waitFor")
+                        process)
+            (loop :with b :do
+               (setq b
+                     (java:jcall (java:jmethod "java.io.InputStream" "read")
+                                 output))
+               :until (member b '(-1 #x0a))     ; Either EOF or LF
+               :collecting (code-char b) :into result
+               :finally (return
+                          (parse-integer (coerce result 'string)))))
+        (t () 0))))
 
 (defimplementation lisp-implementation-type-name ()
   "armedbear")
@@ -265,11 +336,11 @@
 
 (defimplementation arglist (fun)
   (cond ((symbolp fun)
-          (multiple-value-bind (arglist present) 
+          (multiple-value-bind (arglist present)
               (sys::arglist fun)
             (when (and (not present)
                        (fboundp fun)
-                       (typep (symbol-function fun) 
+                       (typep (symbol-function fun)
                               'standard-generic-function))
               (setq arglist
                     (mop::generic-function-lambda-list (symbol-function fun))
@@ -279,11 +350,24 @@
         (t :not-available)))
 
 (defimplementation function-name (function)
-  (nth-value 2 (function-lambda-expression function)))
+  (if (fboundp 'sys::any-function-name)
+      ;; abcl-1.5.0
+      (sys::any-function-name function)
+      ;; pre abcl-1.5.0
+      (nth-value 2 (function-lambda-expression function))))
 
 (defimplementation macroexpand-all (form &optional env)
   (ext:macroexpand-all form env))
 
+(defimplementation collect-macro-forms (form &optional env)
+  ;; Currently detects only normal macros, not compiler macros.
+  (declare (ignore env))
+  (with-collected-macro-forms (macro-forms)
+      (handler-bind ((warning #'muffle-warning))
+        (ignore-errors
+          (compile nil `(lambda () ,(macroexpand-all form env)))))
+    (values macro-forms nil)))
+
 (defimplementation describe-symbol-for-emacs (symbol)
   (let ((result '()))
     (flet ((doc (kind &optional (sym symbol))
@@ -297,10 +381,10 @@
       (when (fboundp symbol)
         (maybe-push
          (cond ((macro-function symbol)     :macro)
-              ((special-operator-p symbol) :special-operator)
-              ((typep (fdefinition symbol) 'generic-function)
+               ((special-operator-p symbol) :special-operator)
+               ((typep (fdefinition symbol) 'generic-function)
                 :generic-function)
-              (t :function))
+               (t :function))
          (doc 'function)))
       (maybe-push
        :class (if (find-class symbol nil)
@@ -318,26 +402,36 @@
 
 (defimplementation describe-definition (symbol namespace)
   (ecase namespace
-    (:variable 
+    (:variable
      (describe symbol))
     ((:function :generic-function)
      (describe (symbol-function symbol)))
     (:class
      (describe (find-class symbol)))))
 
-
 ;;;; Debugger
 
 ;; Copied from slynk-sbcl.lisp.
+#+abcl-introspect
+(defvar sys::*caught-frames*)
 ;;
 ;; Notice that *INVOKE-DEBUGGER-HOOK* is tried before *DEBUGGER-HOOK*,
 ;; so we have to make sure that the latter gets run when it was
 ;; established locally by a user (i.e. changed meanwhile.)
 (defun make-invoke-debugger-hook (hook)
   (lambda (condition old-hook)
-    (if *debugger-hook*
-        (funcall *debugger-hook* condition old-hook)
-        (funcall hook condition old-hook))))
+    (prog1 (let (#+abcl-introspect
+                 (sys::*caught-frames* nil))
+             ;; the next might be the right thing for earlier lisps but I 
don't know
+             ;;; XXX probably doesn't work in absence of ABCL-INTROSPECT on 
abcl-1.4 and earlier
+             (let (#+abcl-introspect
+                   (sys::*saved-backtrace*
+                    (if (fboundp 'sys::new-backtrace)
+                        (sys::new-backtrace condition)
+                        (sys::backtrace))))
+               (if *debugger-hook*
+                   (funcall *debugger-hook* condition old-hook)
+                   (funcall hook condition old-hook)))))))
 
 (defimplementation call-with-debugger-hook (hook fun)
   (let ((*debugger-hook* hook)
@@ -348,21 +442,28 @@
   (setq *debugger-hook* function)
   (setq sys::*invoke-debugger-hook* (make-invoke-debugger-hook function)))
 
-(defvar *sly-db-topframe*)
+(defvar *sldb-topframe*)
 
 (defimplementation call-with-debugging-environment (debugger-loop-fn)
   (let* ((magic-token (intern "SLYNK-DEBUGGER-HOOK" 'slynk))
-         (*sly-db-topframe* 
-          (second (member magic-token (sys:backtrace)
-                          :key (lambda (frame) 
-                                 (first (sys:frame-to-list frame)))))))
+         (*sldb-topframe* 
+           (or
+            (second (member magic-token
+                            #+abcl-introspect sys::*saved-backtrace*
+                            #-abcl-introspect (sys:backtrace)
+                            :key (lambda (frame)
+                                   (first (sys:frame-to-list frame)))))
+            (car sys::*saved-backtrace*)))
+         #+#.(slynk/backend:with-symbol *debug-condition* 'ext)
+         (ext::*debug-condition* slynk::*slynk-debugger-condition*))
     (funcall debugger-loop-fn)))
 
 (defun backtrace (start end)
   "A backtrace without initial SLYNK frames."
-  (let ((backtrace (sys:backtrace)))
-    (subseq (or (member *sly-db-topframe* backtrace) backtrace)
-            start end)))
+  (let ((backtrace
+         #+abcl-introspect sys::*saved-backtrace*
+         #-abcl-introspect (sys:backtrace)))
+    (subseq (or (member *sldb-topframe* backtrace) backtrace) start end)))
 
 (defun nth-frame (index)
   (nth index (backtrace 0 nil)))
@@ -371,74 +472,119 @@
   (let ((end (or end most-positive-fixnum)))
     (backtrace start end)))
 
+;; Don't count on JSS being loaded, but if it is then there's some more stuff 
we can do
++#+#.(slynk/backend:with-symbol 'invoke-restargs 'jss)
+(defun jss-p ()
+  (and (member "JSS" *modules* :test 'string=) (intern "INVOKE-RESTARGS" 
"JSS")))
+
++#+#.(slynk/backend:with-symbol 'invoke-restargs 'jss)
+(defun matches-jss-call (form)
+  (flet ((gensymp (s) (and (symbolp s) (null (symbol-package s))))
+         (invokep (s)  (and (symbolp s) (eq s (jss-p)))))
+    (let ((method
+            (slynk/match::select-match 
+             form
+             (((LAMBDA ((#'gensymp a) &REST (#'gensymp b)) 
+                 ((#'invokep fun) (#'stringp c) (#'gensymp d) (#'gensymp e) . 
args)) . args) '=> c)
+             (other nil))))
+      method)))
+
+#-abcl-introspect
 (defimplementation print-frame (frame stream)
   (write-string (sys:frame-to-string frame)
                 stream))
 
-;;; Sorry, but can't seem to declare DEFIMPLEMENTATION under FLET.
-;;; --ME 20150403
+;; Use princ cs write-string for lisp frames as it respects (print-object 
(function t))
+;; Rewrite jss expansions to their unexpanded state
+;; Show java exception frames up to where a java exception happened with a "!" 
+;; Check if a java class corresponds to a lisp function and tell us if to
+(defvar *debugger-package* (find-package 'cl-user))
+
+#+abcl-introspect
+(defimplementation print-frame (frame stream)
+  ;; make clear which functions aren't Common Lisp. Otherwise uses
+  ;; default package, which is invisible
+  (let ((*package* (or *debugger-package* *package*))) 
+    (if (typep frame 'sys::lisp-stack-frame)
+        (if (not (jss-p))
+            (princ (system:frame-to-list frame) stream)
+            ;; rewrite jss forms as they would be written
+            (let ((form (system:frame-to-list frame)))
+              (if (eq (car form) (jss-p))
+                  (format stream "(#~s ~{~s~^~})" (second form) (list* (third  
form) (fourth form)))
+                  (loop initially  (write-char #\( stream)
+                        for (el . rest) on form
+                        for method =  (slynk/abcl::matches-jss-call el)
+                        do
+                           (cond (method 
+                                  (format stream "(#~s ~{~s~^~})" method (cdr 
el)))
+                                 (t
+                                  (prin1 el stream)))
+                           (unless (null rest) (write-char #\space stream))
+                        finally (write-char #\) stream)))))
+        (let ((classname (getf (sys:frame-to-list frame) :class)))
+          (if (and (fboundp 'sys::javaframe)
+                   (member (sys::javaframe frame) sys::*caught-frames* :test 
'equal))
+              (write-string "! " stream))
+          (write-string (sys:frame-to-string frame) stream)
+          (if (and classname (sys::java-class-lisp-function classname))
+              (format stream " = ~a" (sys::java-class-lisp-function 
classname)))))))
+
+;;; Machinery for DEFIMPLEMENTATION
+;;; FIXME can't seem to use FLET forms with DEFIMPLEMENTATION --ME 20150403
 (defun nth-frame-list (index)
-  (java:jcall "toLispList" (nth-frame index)))
+  (jcall "toLispList" (nth-frame index)))
 
 (defun match-lambda (operator values)
   (jvm::match-lambda-list
    (multiple-value-list
     (jvm::parse-lambda-list (ext:arglist operator)))
    values))
-
+  
 (defimplementation frame-locals (index)
-  (loop
-     :for id :upfrom 0
-     :with frame = (nth-frame-list index)
-     :with operator = (first frame)
-     :with values = (rest frame)
-     :with arglist = (if (and operator (consp values) (not (null values)))
-                         (handler-case
-                             (match-lambda operator values)
-                           (jvm::lambda-list-mismatch (e)
-                             :lambda-list-mismatch))
-                         :not-available)
-     :for value :in values
-     :collecting (list
-                  :name (if (not (keywordp arglist))
-                            (first (nth id arglist))
-                            (format nil "arg~A" id))
-                  :id id
-                  :value value)))
+  (let ((frame (nth-frame index)))
+    ;; FIXME introspect locals in SYS::JAVA-STACK-FRAME
+    (when (typep frame 'sys::lisp-stack-frame) 
+       (loop
+          :for id :upfrom 0
+          :with frame = (nth-frame-list index)
+          :with operator = (first frame)
+          :with values = (rest frame)
+          :with arglist = (if (and operator (consp values) (not (null values)))
+                              (handler-case (match-lambda operator values)
+                                (jvm::lambda-list-mismatch (e) (declare(ignore 
e))
+                                  :lambda-list-mismatch))
+                              :not-available)
+          :for value :in values
+          :collecting (list
+                       :name (if (not (keywordp arglist))
+                                 (first (nth id arglist))
+                                 (format nil "arg~A" id))
+                       :id id
+                       :value value)))))
 
 (defimplementation frame-var-value (index id)
-  (elt (rest (java:jcall "toLispList" (nth-frame index))) id))
-
+ (elt (rest (jcall "toLispList" (nth-frame index))) id))
 
-#+nil
+#+abcl-introspect
 (defimplementation disassemble-frame (index)
-  (disassemble (debugger:frame-function (nth-frame index))))
-
+  (sys::disassemble (frame-function (nth-frame index))))
+
+(defun frame-function (frame)
+  (let ((list (sys::frame-to-list frame)))
+    (cond 
+      ((keywordp (car list))
+       (find (getf list :method) 
+             (jcall "getDeclaredMethods" (jclass (getf list :class)))
+             :key (lambda(e)(jcall "getName" e)) :test 'equal))
+      (t (car list) ))))
+       
 (defimplementation frame-source-location (index)
   (let ((frame (nth-frame index)))
     (or (source-location (nth-frame index))
         `(:error ,(format nil "No source for frame: ~a" frame)))))
 
-#+nil
-(defimplementation eval-in-frame (form frame-number)
-  (debugger:eval-form-in-context 
-   form
-   (debugger:environment-of-frame (nth-frame frame-number))))
-
-#+nil
-(defimplementation return-from-frame (frame-number form)
-  (let ((frame (nth-frame frame-number)))
-    (multiple-value-call #'debugger:frame-return 
-      frame (debugger:eval-form-in-context 
-             form 
-             (debugger:environment-of-frame frame)))))
-                         
-;;; XXX doesn't work for frames with arguments 
-#+nil
-(defimplementation restart-frame (frame-number)
-  (let ((frame (nth-frame frame-number)))
-    (debugger:frame-retry frame (debugger:frame-function frame))))
-                          
+
 ;;;; Compiler hooks
 
 (defvar *buffer-name* nil)
@@ -449,18 +595,18 @@
 (defvar *abcl-signaled-conditions*)
 
 (defun handle-compiler-warning (condition)
-  (let ((loc (when (and jvm::*compile-file-pathname* 
+  (let ((loc (when (and jvm::*compile-file-pathname*
                         system::*source-position*)
                (cons jvm::*compile-file-pathname* system::*source-position*))))
     ;; filter condition signaled more than once.
-    (unless (member condition *abcl-signaled-conditions*) 
-      (push condition *abcl-signaled-conditions*) 
+    (unless (member condition *abcl-signaled-conditions*)
+      (push condition *abcl-signaled-conditions*)
       (signal 'compiler-condition
               :original-condition condition
               :severity :warning
               :message (format nil "~A" condition)
               :location (cond (*buffer-name*
-                               (make-location 
+                               (make-location
                                 (list :buffer *buffer-name*)
                                 (list :offset *buffer-start-position* 0)))
                               (loc
@@ -468,21 +614,21 @@
                                  (make-location
                                   (list :file (namestring (truename file)))
                                   (list :position (1+ pos)))))
-                              (t  
+                              (t
                                (make-location
                                 (list :file (namestring *compile-filename*))
                                 (list :position 1))))))))
 
 (defimplementation slynk-compile-file (input-file output-file
-                                                  load-p external-format
-                                                  &key policy)
+                                       load-p external-format
+                                       &key policy)
   (declare (ignore external-format policy))
   (let ((jvm::*resignal-compiler-warnings* t)
         (*abcl-signaled-conditions* nil))
     (handler-bind ((warning #'handle-compiler-warning))
       (let ((*buffer-name* nil)
             (*compile-filename* input-file))
-        (multiple-value-bind (fn warn fail) 
+        (multiple-value-bind (fn warn fail)
             (compile-file input-file :output-file output-file)
           (values fn warn
                   (and fn load-p
@@ -493,7 +639,7 @@
   (declare (ignore filename line column policy))
   (let ((jvm::*resignal-compiler-warnings* t)
         (*abcl-signaled-conditions* nil))
-    (handler-bind ((warning #'handle-compiler-warning))                 
+    (handler-bind ((warning #'handle-compiler-warning))
       (let ((*buffer-name* buffer)
             (*buffer-start-position* position)
             (*buffer-string* string)
@@ -503,59 +649,132 @@
                                (format nil "(~S () ~A)" 'lambda string))))
         t))))
 
-#|
-;;;; Definition Finding
-
-(defun find-fspec-location (fspec type)
-  (let ((file (excl::fspec-pathname fspec type)))
-    (etypecase file
-      (pathname
-       (let ((start (scm:find-definition-in-file fspec type file)))
-         (make-location (list :file (namestring (truename file)))
-                        (if start
-                            (list :position (1+ start))
-                            (list :function-name (string fspec))))))
-      ((member :top-level)
-       (list :error (format nil "Defined at toplevel: ~A" fspec)))
-      (null 
-       (list :error (format nil "Unkown source location for ~A" fspec))))))
-
-(defun fspec-definition-locations (fspec)
-  (let ((defs (excl::find-multiple-definitions fspec)))
-    (loop for (fspec type) in defs 
-          collect (list fspec (find-fspec-location fspec type)))))
-
-(defimplementation find-definitions (symbol)
-  (fspec-definition-locations symbol))
-|#
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; source location and users of it
 
 (defgeneric source-location (object))
 
+;; try to find some kind of source for internals
+#+abcl-introspect
+(defun implementation-source-location (arg)
+  (let ((function (cond ((functionp arg)
+                         arg)
+                        ((and (symbolp arg) (fboundp arg)) 
+                         (or (symbol-function arg) (macro-function arg))))))
+    (when (typep function 'generic-function)
+      (setf function (mop::funcallable-instance-function function)))
+    ;; functions are execute methods of class
+    (when (or (functionp function) (special-operator-p arg))
+      (let ((fclass (jcall "getClass" function)))
+        (let ((classname (jcall "getName" fclass)))
+          (destructuring-bind (class local)
+              (if (find #\$ classname)
+                  (split-string classname "\\$")
+                  (list classname (jcall "replaceFirst" classname 
"([^.]*\\.)*" "")))
+            (unless (member local '("MacroObject" "CompiledClosure" "Closure") 
:test 'equal)
+            ;; look for java source
+              (let* ((partial-path   (substitute #\/ #\. class))
+                     (java-path (concatenate 'string partial-path ".java"))
+                     (found-in-source-path (find-file-in-path java-path 
*source-path*))) 
+                ;; snippet for finding the internal class within the file
+                (if found-in-source-path 
+                    `((:primitive ,local)
+                      (:location ,found-in-source-path
+                                 (:line 0)
+                                 (:snippet ,(format nil "class ~a" local))))
+                    ;; if not, look for the class file, and hope that
+                    ;; emacs is configured to disassemble class entries
+                    ;; in jars.
+
+                    ;; Alan uses jdc.el
+                    ;; 
<https://github.com/m0smith/dotfiles/blob/master/.emacs.d/site-lisp/jdc.el>
+                    ;; with jad <https://github.com/moparisthebest/jad>
+                    ;; Also (setq sys::*disassembler* "jad -a -p")
+                    (let ((class-in-source-path 
+                           (find-file-in-path (concatenate 'string 
partial-path ".class") *source-path*)))
+                      ;; no snippet, since internal class is in its own file
+                      (when class-in-source-path
+                        `(:primitive (:location ,class-in-source-path (:line 
0) nil)))))))))))))
+
+#+abcl-introspect
+(defun get-declared-field (class fieldname)
+  (find fieldname (jcall "getDeclaredFields" class) :key 'jfield-name :test 
'equal))
+
+#+abcl-introspect
+(defun symbol-defined-in-java (symbol)
+  (loop  with internal-name1 = (jcall "replaceAll" (jcall "replaceAll" (string 
symbol) "\\*" "") "-" "_")
+         with internal-name2 = (jcall "replaceAll" (jcall "replaceAll" (string 
symbol) "\\*" "_") "-" "_")
+         for class in 
+                   (load-time-value (mapcar
+                                     'jclass
+                                     '("org.armedbear.lisp.Package"
+                                       "org.armedbear.lisp.Symbol"
+                                       "org.armedbear.lisp.Debug"
+                                       "org.armedbear.lisp.Extensions"
+                                       "org.armedbear.lisp.JavaObject"
+                                       "org.armedbear.lisp.Lisp"
+                                       "org.armedbear.lisp.Pathname"
+                                       "org.armedbear.lisp.Site")))
+           thereis 
+           (or (get-declared-field class internal-name1)
+               (get-declared-field class internal-name2))))
+
+#+abcl-introspect
+(defun maybe-implementation-variable (s)
+  (let ((field (symbol-defined-in-java s)))
+    (and field
+         (let ((class (jcall "getName" (jcall "getDeclaringClass" field))))
+           (let* ((partial-path (substitute #\/ #\. class))
+                  (java-path (concatenate 'string partial-path ".java"))
+                  (found-in-source-path (find-file-in-path java-path 
*source-path*)))
+             (when found-in-source-path
+               `(symbol (:location ,found-in-source-path (:line 0)
+                                   (:snippet ,(format nil  "~s" (string 
s)))))))))))
+
+#+abcl-introspect
+(defun if-we-have-to-choose-one-choose-the-function (sources)
+  (or (loop for spec in  sources
+            for (dspec) = spec
+            when (and (consp dspec) (eq (car dspec) :function))
+            when (and (consp dspec) (member (car dspec) 
'(:slynk-implementation :function)))
+                 do (return-from if-we-have-to-choose-one-choose-the-function 
spec))
+      (car sources)))
+
 (defmethod source-location ((symbol symbol))
-  (when (pathnamep (ext:source-pathname symbol))
-    (let ((pos (ext:source-file-position symbol))
-          (path (namestring (ext:source-pathname symbol))))
-      (cond ((ext:pathname-jar-p path)
-             `(:location
-               ;; strip off "jar:file:" = 9 characters
-               (:zip ,@(split-string (subseq path 9) "!/"))
-               ;; pos never seems right. Use function name.
-               (:function-name ,(string symbol))
-               (:align t)))
-            ((equal (pathname-device (ext:source-pathname symbol)) 
"emacs-buffer")
-             ;; conspire to keep the buffer name in a pathname
-             ;; whose device is "emacs-buffer".
-             `(:location
-                (:buffer ,(pathname-name (ext:source-pathname symbol)))
-                (:function-name ,(string symbol))
-                (:align t)))
-            (t
-             `(:location
-                (:file ,path)
-                ,(if pos
-                     (list :position (1+ pos))
-                     (list :function-name (string symbol)))
-                (:align t)))))))
+  (or #+abcl-introspect
+      (let ((maybe (if-we-have-to-choose-one-choose-the-function (get symbol 
'sys::source))))
+        (and maybe (second (sly-location-from-source-annotation symbol 
maybe))))
+      ;; This below should be obsolete - it uses the old sys:%source
+      ;; leave it here for now just in case
+      (and (pathnamep (ext:source-pathname symbol))
+           (let ((pos (ext:source-file-position symbol))
+                 (path (namestring (ext:source-pathname symbol))))
+             ; boot.lisp gets recorded wrong
+             (when (equal path "boot.lisp")
+                 (setq path (second (find-file-in-path 
"org/armedbear/lisp/boot.lisp" *source-path*))))
+             (cond ((ext:pathname-jar-p path)
+                    `(:location
+                      ;; strip off "jar:file:" = 9 characters
+                      (:zip ,@(split-string (subseq path 9) "!/"))
+                      ;; pos never seems right. Use function name.
+                      (:function-name ,(string symbol))
+                      (:align t)))
+                   ((equal (pathname-device (ext:source-pathname symbol)) 
"emacs-buffer")
+                    ;; conspire with slynk-compile-string to keep the buffer
+                    ;; name in a pathname whose device is "emacs-buffer".
+                    `(:location
+                      (:buffer ,(pathname-name (ext:source-pathname symbol)))
+                      (:function-name ,(string symbol))
+                      (:align t)))
+                   (t
+                    `(:location
+                      (:file ,path)
+                      ,(if pos
+                           (list :position (1+ pos))
+                           (list :function-name (string symbol)))
+                      (:align t))))))
+      #+abcl-introspect
+      (second (implementation-source-location symbol))))
 
 (defmethod source-location ((frame sys::java-stack-frame))
   (destructuring-bind (&key class method file line) (sys:frame-to-list frame)
@@ -565,7 +784,7 @@
                                      (butlast (split-string class "\\."))
                                      file)))
                       (find-file-in-path f *source-path*)))))
-      (and file 
+      (and file
            `(:location ,file (:line ,line) ())))))
 
 (defmethod source-location ((frame sys::lisp-stack-frame))
@@ -577,11 +796,27 @@
       (symbol (source-location operator)))))
 
 (defmethod source-location ((fun function))
+  (if #+abcl-introspect
+      (sys::local-function-p fun)
+      #-abcl-introspect
+      nil
+      (source-location (sys::local-function-owner fun))
+      (let ((name (function-name fun)))
+        (and name (source-location name)))))
+
+(defmethod source-location ((method method))
+  #+abcl-introspect
+  (let ((found 
+         (find `(:method ,@(sys::method-spec-list method))
+               (get (function-name method) 'sys::source)
+               :key 'car :test 'equalp)))
+    (and found (second (sly-location-from-source-annotation (function-name 
method) found))))
+  #-abcl-introspect
   (let ((name (function-name fun)))
     (and name (source-location name))))
 
 (defun system-property (name)
-  (java:jstatic "getProperty" "java.lang.System" name))
+  (jstatic "getProperty" "java.lang.System" name))
 
 (defun pathname-parent (pathname)
   (make-pathname :directory (butlast (pathname-directory pathname))))
@@ -590,18 +825,18 @@
   (eq (car (pathname-directory pathname)) ':absolute))
 
 (defun split-string (string regexp)
-  (coerce 
-   (java:jcall (java:jmethod "java.lang.String" "split" "java.lang.String")
+  (coerce
+   (jcall (jmethod "java.lang.String" "split" "java.lang.String")
                string regexp)
    'list))
 
 (defun path-separator ()
-  (java:jfield "java.io.File" "pathSeparator"))
+  (jfield "java.io.File" "pathSeparator"))
 
 (defun search-path-property (prop-name)
   (let ((string (system-property prop-name)))
     (and string
-         (remove nil 
+         (remove nil
                  (mapcar #'truename
                          (split-string string (path-separator)))))))
 
@@ -616,23 +851,25 @@
           (search-path-property "sun.boot.class.path")))
 
 (defvar *source-path*
-  (append (search-path-property "user.dir")
-          (jdk-source-path)
-          ;;(list (truename "/scratch/abcl/src"))
-          )
-  "List of directories to search for source files.")
+  (remove nil 
+          (append (search-path-property "user.dir")
+                  (jdk-source-path)
+                  ;; include lib jar files. contrib has lisp code. Would be 
good to build abcl.jar with source code as well
+                  #+abcl-introspect
+                  (list (sys::find-system-jar)
+                        (sys::find-contrib-jar))))
+                  ;; you should tell sly where the abcl sources are. In 
.slynk.lisp I have:
+                  ;; (push (probe-file "/Users/alanr/repos/abcl/src/") 
*SOURCE-PATH*)
+"List of directories to search for source files.")
 
 (defun zipfile-contains-p (zipfile-name entry-name)
-  (let ((zipfile (java:jnew (java:jconstructor "java.util.zip.ZipFile" 
+  (let ((zipfile (jnew (jconstructor "java.util.zip.ZipFile"
                                                "java.lang.String")
                             zipfile-name)))
-    (java:jcall
-     (java:jmethod "java.util.zip.ZipFile" "getEntry" "java.lang.String")
+    (jcall
+     (jmethod "java.util.zip.ZipFile" "getEntry" "java.lang.String")
      zipfile entry-name)))
 
-;; (find-file-in-path "java/lang/String.java" *source-path*)
-;; (find-file-in-path "Lisp.java" *source-path*)
-
 ;; Try to find FILENAME in PATH.  If found, return a file spec as
 ;; needed by Emacs.  We also look in zip files.
 (defun find-file-in-path (filename path)
@@ -640,115 +877,549 @@
              (cond ((not (pathname-type dir))
                     (let ((f (probe-file (merge-pathnames filename dir))))
                       (and f `(:file ,(namestring f)))))
-                   ((equal (pathname-type dir) "zip")
+                   ((member (pathname-type dir) '("zip" "jar") :test 'equal)
                     (try-zip dir))
                    (t (error "strange path element: ~s" path))))
            (try-zip (zip)
              (let* ((zipfile-name (namestring (truename zip))))
                (and (zipfile-contains-p zipfile-name filename)
-                    `(:dir ,zipfile-name  ,filename)))))
+                    `(#+abcl-introspect
+                      :zip
+                      #-abcl-introspect
+                      :dir
+                      ,zipfile-name  ,filename)))))
     (cond ((pathname-absolute-p filename) (probe-file filename))
           (t
            (loop for dir in path
                  if (try dir) return it)))))
 
+(defparameter *definition-types*
+  '(:variable defvar
+    :constant defconstant
+    :type deftype
+    :symbol-macro define-symbol-macro
+    :macro defmacro
+    :compiler-macro define-compiler-macro
+    :function defun
+    :generic-function defgeneric
+    :method defmethod
+    :setf-expander define-setf-expander
+    :structure defstruct
+    :condition define-condition
+    :class defclass
+    :method-combination define-method-combination
+    :package defpackage
+    :transform :deftransform
+    :optimizer :defoptimizer
+    :vop :define-vop
+    :source-transform :define-source-transform
+    :ir1-convert :def-ir1-translator
+    :declaration declaim
+    :alien-type :define-alien-type)
+  "Map SB-INTROSPECT definition type names to Sly-friendly forms")
+
+(defun definition-specifier (type)
+  "Return a pretty specifier for NAME representing a definition of type TYPE."
+  (or (if (and (consp type) (getf *definition-types* (car type)))
+       `(,(getf *definition-types* (car type)) ,(second type) ,@(third type) 
,@(cdddr type))
+       (getf *definition-types* type))
+      type))
+
+(defun stringify-method-specs (type)
+  "return a (:method ..) location for sly"
+  (let ((*print-case* :downcase))
+    (flet ((p (a) (princ-to-string a)))
+      (destructuring-bind (name qualifiers specializers) (cdr type)
+        `(,(car type) ,(p name) ,(mapcar #'p specializers) ,@(mapcar #'p 
qualifiers))))))
+
+;; for abcl source, check if it is still there, and if not, look in abcl jar 
instead
+(defun maybe-redirect-to-jar (path)
+  (setq path (namestring path))
+  (if (probe-file path)
+      path
+      (if (search "/org/armedbear/lisp" path :test 'string=)
+          (let ((jarpath (format nil "jar:file:~a!~a" (namestring 
(sys::find-system-jar)) 
+                                 (subseq path (search "/org/armedbear/lisp" 
path)))))
+            (if (probe-file jarpath) 
+                jarpath
+                path))
+          path)))
+
+#-abcl-introspect
 (defimplementation find-definitions (symbol)
   (ext:resolve symbol)
   (let ((srcloc (source-location symbol)))
     (and srcloc `((,symbol ,srcloc)))))
 
-#| 
-Uncomment this if you have patched xref.lisp, as in 
-http://article.gmane.org/gmane.lisp.sly.devel/2425
-Also, make sure that xref.lisp is loaded by modifying the armedbear
-part of *sysdep-pathnames* in slynk.loader.lisp. 
-
-;;;; XREF
-(setq pxref:*handle-package-forms* '(cl:in-package))
-
-(defmacro defxref (name function)
-  `(defimplementation ,name (name)
-    (xref-results (,function name))))
-
-(defxref who-calls      pxref:list-callers)
-(defxref who-references pxref:list-readers)
-(defxref who-binds      pxref:list-setters)
-(defxref who-sets       pxref:list-setters)
-(defxref list-callers   pxref:list-callers)
-(defxref list-callees   pxref:list-callees)
-
-(defun xref-results (symbols)
-  (let ((xrefs '()))
-    (dolist (symbol symbols)
-      (push (list symbol (cadar (source-location symbol))) xrefs))
-    xrefs))
-|#
-
+#+abcl-introspect
+(defimplementation find-definitions (symbol)
+  (when (stringp symbol) 
+    ;; allow a string to be passed. If it is package prefixed, remove the 
prefix 
+    (setq symbol (intern (string-upcase 
+                          (subseq symbol (1+ (or (position #\: symbol 
:from-end t) -1))))
+                         'keyword)))
+  (let ((sources nil)
+        (implementation-variables nil)
+        (implementation-functions nil))
+    (loop for package in (list-all-packages)
+          for sym = (find-symbol (string symbol) package)
+          when (and sym (equal (symbol-package sym) package))
+            do
+               (when (sys::autoloadp symbol)
+                 (sys::resolve symbol))
+               (let ((source (or (get sym 'ext::source) (get sym 
'sys::source)))
+                     (i-var  (maybe-implementation-variable sym))
+                     (i-fun  (implementation-source-location sym)))
+                 (when source
+                   (setq sources (append sources (or (get sym 'ext::source) 
(get sym 'sys::source)))))
+                 (when i-var
+                   (push i-var implementation-variables))
+                 (when i-fun
+                   (push i-fun implementation-functions))))
+    (setq sources (remove-duplicates sources :test 'equalp))
+    (append (remove-duplicates implementation-functions :test 'equalp)
+            (mapcar (lambda(s) (sly-location-from-source-annotation symbol s)) 
sources)
+            (remove-duplicates implementation-variables :test 'equalp))))
+
+(defun sly-location-from-source-annotation (sym it)
+  (destructuring-bind (what path pos) it
+
+    (let* ((isfunction
+            ;; all of these are (defxxx forms, which is what :function 
locations look for in sly
+            (and (consp what) (member (car what)
+                                      '(:function :generic-function :macro 
:class :compiler-macro
+                                        :type :constant :variable :package 
:structure :condition))))
+           (ismethod (and (consp what) (eq (car what) :method)))
+           (<position> (cond (isfunction (list :function-name (princ-to-string 
(second what))))
+                                             (ismethod (stringify-method-specs 
what))
+                                             (t (list :position (1+ (or pos 
0))))))
+
+           (path2 (if (eq path :top-level)
+                      ;; this is bogus - figure out some way to guess which is 
the repl associated with :toplevel
+                      ;; or get rid of this
+                      "emacs-buffer:*sly-repl*"
+                      (maybe-redirect-to-jar path))))
+      (when (atom what)
+        (setq what (list what sym)))
+      (list (definition-specifier what)
+            (if (ext:pathname-jar-p path2)
+                `(:location
+                  ;; JAR-PATHNAME stores the PATHNAME of the jar file as first 
element of a list DEVICE
+                  (:zip ,@(pathname-device path2))
+                  ;; pos never seems right. Use function name.
+                  ,<position>
+                  (:align t))
+                ;; conspire with slynk-compile-string to keep the
+                ;; buffer name in a pathname whose device is
+                ;; "emacs-buffer".
+                  (if (eql 0 (search "emacs-buffer:" path2))
+                      `(:location
+                        (:buffer ,(subseq path2  (load-time-value (length 
"emacs-buffer:"))))
+                        ,<position>
+                        (:align t))
+                      `(:location
+                        (:file ,path2)
+                        ,<position>
+                        (:align t))))))))
+
+#+abcl-introspect
+(defimplementation list-callers (thing)
+  (loop for caller in (sys::callers thing)
+        when (typep caller 'method)
+          append (let ((name (mop:generic-function-name
+                              (mop:method-generic-function caller))))
+                   (mapcar (lambda(s) (sly-location-from-source-annotation 
thing s))
+                           (remove `(:method ,@(sys::method-spec-list caller))
+                                   (get 
+                                    (if (consp name) (second name) name)
+                                    'sys::source)
+                                   :key 'car :test-not 'equalp)))
+        when (symbolp caller)
+          append   (mapcar (lambda(s) (sly-location-from-source-annotation 
caller s))
+                           (get caller 'sys::source))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; Inspecting
+
+;;; BEGIN FIXME move into generalized Slynk infrastructure, or add to contrib 
mechanism
+;; this is only for hyperspec request in an inspector window
+;; TODO have sly-hyperspec-lookup respect this variable too
+(defvar *sly-inspector-hyperspec-in-browser* t
+  "If t then invoking hyperspec within the inspector browses the hyperspec in 
an emacs buffer, otherwise respecting the value of browse-url-browser-function")
+
+(defun hyperspec-do (name)
+  (let ((form `(let ((browse-url-browser-function 
+                       ,(if *sly-inspector-hyperspec-in-browser* 
+                            '(lambda(a v) (eww a))
+                            'browse-url-browser-function)))
+                        (sly-hyperdoc-lookup ,name))))
+    (slynk::eval-in-emacs form t)))
+;;; END FIXME move into generalized Slynk infrastructure, or add to contrib 
mechanism
+
+;;; Although by convention toString() is supposed to be a
+;;; non-computationally expensive operation this isn't always the
+;;; case, so make its computation a user interaction.
+(defparameter *to-string-hashtable* (make-hash-table :weakness :key))
+
 (defmethod emacs-inspect ((o t))
-  (let ((parts (sys:inspected-parts o)))
-    `("The object is of type " ,(symbol-name (type-of o)) "." (:newline)
-      ,@(if parts
-           (loop :for (label . value) :in parts
-              :appending (label-value-line label value))
-           (list "No inspectable parts, dumping output of CL:DESCRIBE:" 
-                 '(:newline) 
-                  (with-output-to-string (desc) (describe o desc)))))))
+  (let* ((type (type-of o))
+         (class (ignore-errors (find-class type)))
+         (jclass (and (typep  class 'sys::built-in-class)
+                      (jcall "getClass" o))))
+    (let ((parts (sys:inspected-parts o)))
+      `((:label "Type: ") (:value ,(or class type)) (:Newline)
+        ,@(if jclass 
+              `((:label "Java type: ") (:value ,jclass) (:newline)))
+        ,@(if parts
+              (loop :for (label . value) :in parts
+                 :appending (list
+                             (list :label (string-capitalize label))
+                             ": "
+                             (list :value value (princ-to-string value)) 
'(:newline)))
+              (list '(:label "No inspectable parts, dumping output of 
CL:DESCRIBE:")
+                    '(:newline)
+                    (with-output-to-string (desc) (describe o desc))))))))
+
+(defmethod emacs-inspect ((string string))
+  (slynk::lcons* 
+   '(:label "Value: ")  `(:value ,string ,(concatenate 'string "\"" string 
"\""))  '(:newline)
+   #+abcl-introspect ;; ??? This doesn't appear depend on ABCL-INTROSPECT.  
Why disable?
+   `(:action "[Edit in emacs buffer]" ,(lambda() (slynk::ed-in-emacs `(:string 
,string))))
+   '(:newline)
+   (if (ignore-errors (jclass string))
+       `(:line "Names java class" ,(jclass string))
+       "")
+   #+abcl-introspect
+   (if (and (jss-p) 
+            (stringp (funcall (intern "LOOKUP-CLASS-NAME" :jss) string 
:return-ambiguous t :muffle-warning t)))
+       `(:multiple
+         (:label "Abbreviates java class: ")
+         ,(let ((it (funcall (intern "LOOKUP-CLASS-NAME" :jss) string 
:return-ambiguous t :muffle-warning t)))
+           `(:value ,(jclass it)))
+         (:newline))
+       "")
+   (if (ignore-errors (find-package (string-upcase string)))
+       `(:line "Names package" ,(find-package (string-upcase string)))
+       "")
+   (let ((symbols (loop for p in (list-all-packages)
+                        for found = (find-symbol (string-upcase string))
+                        when (and found (eq (symbol-package found) p)
+                                  (or (fboundp found)
+                                      (boundp found)
+                                      (symbol-plist found)
+                                      (ignore-errors (find-class found))))
+                          collect found)))
+     (if symbols
+         `(:multiple (:label "Names symbols: ") 
+                     ,@(loop for s in symbols
+                             collect
+                             (Let ((*package* (find-package :keyword))) 
+                               `(:value ,s ,(prin1-to-string s))) collect " ") 
(:newline))
+         ""))
+   (call-next-method)))
+
+#+#.(slynk/backend:with-symbol 'java-exception 'java)
+(defmethod emacs-inspect ((o java:java-exception))
+  (append (call-next-method)
+          (list '(:newline) '(:label "Stack trace")
+                      '(:newline)
+                      (let ((w (jnew "java.io.StringWriter"))) 
+                        (jcall "printStackTrace" (java:java-exception-cause o) 
(jnew "java.io.PrintWriter" w))
+                        (jcall "toString" w)))))
 
 (defmethod emacs-inspect ((slot mop::slot-definition))
-  `("Name: " 
+  `("Name: "
     (:value ,(mop:slot-definition-name slot))
     (:newline)
     "Documentation:" (:newline)
     ,@(when (slot-definition-documentation slot)
             `((:value ,(slot-definition-documentation slot)) (:newline)))
     "Initialization:" (:newline)
-    "  Args: " (:value ,(mop:slot-definition-initargs slot)) (:newline)
-    "  Form: "  ,(if (mop:slot-definition-initfunction slot)
+    (:label "  Args: ") (:value ,(mop:slot-definition-initargs slot)) 
(:newline)
+    (:label "  Form: ")  ,(if (mop:slot-definition-initfunction slot)
                      `(:value ,(mop:slot-definition-initform slot))
                      "#<unspecified>") (:newline)
-                     "  Function: " 
+                     (:label "  Function: ")
                      (:value ,(mop:slot-definition-initfunction slot))
                      (:newline)))
 
 (defmethod emacs-inspect ((f function))
   `(,@(when (function-name f)
-            `("Name: " 
-              ,(princ-to-string (function-name f)) (:newline)))
-      ,@(multiple-value-bind (args present) 
-                             (sys::arglist f)
-                             (when present 
-                               `("Argument list: " 
-                                 ,(princ-to-string args) (:newline))))
-      (:newline)
-      #+nil,@(when (documentation f t)
-                   `("Documentation:" (:newline) 
-                                      ,(documentation f t) (:newline)))
+        `((:label "Name: ")
+          ,(princ-to-string (sys::any-function-name f)) (:newline)))
+      ,@(multiple-value-bind (args present) (sys::arglist f)
+          (when present
+            `((:label "Argument list: ")
+              ,(princ-to-string args)
+              (:newline))))
+      #+abcl-introspect
+      ,@(when (documentation f t)
+          `("Documentation:" (:newline)
+                             ,(documentation f t) (:newline)))
       ,@(when (function-lambda-expression f)
-              `("Lambda expression:" 
-                (:newline) ,(princ-to-string
-                             (function-lambda-expression f)) (:newline)))))
+          `((:label "Lambda expression:")
+            (:newline) ,(princ-to-string
+                         (function-lambda-expression f)) (:newline)))
+      (:label "Function java class: ") (:value ,(jcall "getClass" f)) 
(:newline)
+      #+abcl-introspect
+      ,@(when (jcall "isInstance"  (java::jclass 
"org.armedbear.lisp.CompiledClosure") f)
+          `((:label "Closed over: ")
+            ,@(loop
+                 for el in (sys::compiled-closure-context f)
+                 collect `(:value ,el)
+                 collect " ")
+            (:newline)))
+      #+abcl-introspect
+      ,@(when (sys::get-loaded-from f)
+          (list `(:label "Defined in: ")
+                `(:value ,(sys::get-loaded-from f) ,(namestring 
(sys::get-loaded-from f)))
+                '(:newline)))
+      ;; I think this should work in older lisps too -- alanr
+      ,@(let ((fields (jcall "getDeclaredFields" (jcall "getClass" f))))
+          (when (plusp (length fields))
+            (list* '(:label "Internal fields: ") '(:newline)
+                   (loop for field across fields
+                      do (jcall "setAccessible" field t) ;;; not a great idea 
esp. wrt. Java9
+                      append
+                        (let ((value (jcall "get" field f)))
+                          (list "  "
+                                `(:label ,(jcall "getName" field))
+                                ": "
+                                `(:value ,value ,(princ-to-string value))
+                                '(:newline)))))))
+      #+abcl-introspect
+      ,@(when (and (function-name f) (symbolp (function-name f))
+                   (eq (symbol-package (function-name f)) (find-package :cl)))
+          (list '(:newline) (list :action "Lookup in hyperspec"
+                                  (lambda () (hyperspec-do (symbol-name 
(function-name f))))
+                                  :refreshp nil)
+                '(:newline)))))
 
-;;; Although by convention toString() is supposed to be a
-;;; non-computationally expensive operation this isn't always the
-;;; case, so make its computation a user interaction.
-(defparameter *to-string-hashtable* (make-hash-table))
 (defmethod emacs-inspect ((o java:java-object))
+  (if (jinstance-of-p o (jclass "java.lang.Class"))
+      (emacs-inspect-java-class o)
+      (emacs-inspect-java-object o)))
+
+(defvar *sly-tostring-on-demand* nil
+  "Set to t if you don't want to automatically show toString() for java 
objects and instead have inspector action to compute")
+
+(defun static-field? (field)
+  ;; (plusp (logand #"reflect.Modifier.STATIC" (jcall "getModifiers" field)))
+  ;; ugly replace with answer to avoid using jss
+  (plusp (logand 8 (jcall "getModifiers" field))))
+
+(defun inspector-java-object-fields (object)
+  (loop
+     for super = (java::jobject-class object) then (jclass-superclass super)
+     while super
+        ;;; NOTE: In the next line, if I write #'(lambda.... then I
+        ;;; get an error compiling "Attempt to throw to the
+        ;;; nonexistent tag DUPLICATABLE-CODE-P.". WTF
+     for fields
+       = (sort (jcall "getDeclaredFields" super) 'string-lessp :key (lambda(x) 
(jcall "getName" x)))
+     for fromline
+       = nil then (list `(:label "From: ") `(:value ,super  ,(jcall "getName" 
super)) '(:newline))
+     when (and (plusp (length fields)) fromline)
+     append fromline
+     append
+       (loop for this across fields
+          for value = (jcall "get" (progn (jcall "setAccessible" this t) this) 
object)
+          for line = `("  " (:label ,(jcall "getName" this)) ": " (:value 
,value) (:newline))
+          if (static-field? this)
+          append line into statics
+          else append line into members
+          finally (return (append
+                           (if members `((:label "Member fields: ") (:newline) 
,@members))
+                           (if statics `((:label "Static fields: ") (:newline) 
,@statics)))))))
+
+(defun emacs-inspect-java-object (object)
   (let ((to-string (lambda ()
                      (handler-case
-                         (setf (gethash o *to-string-hashtable*)
-                               (java:jcall "toString" o))
+                         (setf (gethash object *to-string-hashtable*)
+                               (jcall "toString" object))
                        (t (e)
-                         (setf (gethash o *to-string-hashtable*)
-                               (format nil 
+                         (setf (gethash object *to-string-hashtable*)
+                               (format nil
                                        "Could not invoke toString(): ~A"
-                                       e)))))))
+                                       e))))))
+        (intended-class (cdr (assoc "intendedClass" (sys::inspected-parts 
object)
+                                    :test 'equal))))
+    `((:label "Class: ")
+      (:value ,(jcall "getClass" object) ,(jcall "getName" (jcall "getClass" 
object) )) (:newline)
+      ,@(if (and intended-class (not (equal intended-class (jcall "getName" 
(jcall "getClass" object)))))
+            `((:label "Intended Class: ")
+              (:value ,(jclass intended-class) ,intended-class) (:newline)))
+      ,@(if (or (gethash object *to-string-hashtable*) (not 
*sly-tostring-on-demand*))
+            (label-value-line "toString()" (funcall to-string))
+            `((:action "[compute toString()]" ,to-string) (:newline)))
+      ,@(inspector-java-object-fields object))))
+
+(defmethod emacs-inspect ((slot mop::slot-definition))
+  `("Name: "
+    (:value ,(mop:slot-definition-name slot))
+    (:newline)
+    "Documentation:" (:newline)
+    ,@(when (slot-definition-documentation slot)
+            `((:value ,(slot-definition-documentation slot)) (:newline)))
+    (:label "Initialization:") (:newline)
+    (:label "  Args: ") (:value ,(mop:slot-definition-initargs slot)) 
(:newline)
+    (:label "  Form: ")
+    ,(if (mop:slot-definition-initfunction slot)
+                     `(:value ,(mop:slot-definition-initform slot))
+                     "#<unspecified>") (:newline)
+                     "  Function: "
+                     (:value ,(mop:slot-definition-initfunction slot))
+                     (:newline)))
+
+(defun inspector-java-fields (class)
+  (loop
+     for super
+       = class then (jclass-superclass super)
+     while super
+     for fields
+       = (jcall "getDeclaredFields" super)
+     for fromline
+       = nil then (list `(:label "From: ") `(:value ,super  ,(jcall "getName" 
super)) '(:newline))
+     when (and (plusp (length fields)) fromline)
+     append fromline
+     append
+       (loop for this across fields
+          for pre = (subseq (jcall "toString" this)
+                            0 
+                            (1+ (position #\. (jcall "toString" this)  
:from-end t)))
+          collect "  "
+          collect (list :value this pre)
+          collect (list :strong-value this (jcall "getName" this) )
+          collect '(:newline))))
+
+(defun inspector-java-methods (class)
+  (loop
+     for super
+       = class then (jclass-superclass super)
+     while super
+     for methods
+       = (jcall "getDeclaredMethods" super)
+     for fromline
+       = nil then (list `(:label "From: ") `(:value ,super  ,(jcall "getName" 
super)) '(:newline))
+     when (and (plusp (length methods)) fromline)
+     append fromline
+     append
+       (loop for this across methods
+          for desc = (jcall "toString" this)
+          for paren =  (position #\( desc)
+          for dot = (position #\. (subseq desc 0 paren) :from-end t)
+          for pre = (subseq desc 0 dot)
+          for name = (subseq desc dot paren)
+          for after = (subseq desc paren)
+          collect "  "
+          collect (list :value this pre)
+          collect (list :strong-value this name)
+          collect (list :value this after)
+          collect '(:newline))))
+
+(defun emacs-inspect-java-class (class)
+  (let ((has-superclasses (jclass-superclass class))
+        (has-interfaces (plusp (length (jclass-interfaces class))))
+        (fields (inspector-java-fields class))
+        (path (jcall "replaceFirst"
+                     (jcall "replaceFirst"  
+                            (jcall "toString" (jcall "getResource" 
+                                                     class
+                                                     (concatenate 'string
+                                                                  "/" 
(substitute #\/ #\. (jcall "getName" class))
+                                                                  ".class")))
+                            "jar:file:" "") "!.*" "")))
+    `((:label ,(format nil "Java Class: ~a" (jcall "getName" class) ))
+      (:newline)
+      ,@(when path (list `(:label ,"Loaded from: ")
+                         `(:value ,path)
+                         " "
+                         `(:action "[open in emacs buffer]" ,(lambda() 
(slynk::ed-in-emacs `( ,path)))) '(:newline)))
+      ,@(if has-superclasses 
+            (list* '(:label "Superclasses: ") (butlast (loop for super = 
(jclass-superclass class) then (jclass-superclass super)
+                            while super collect (list :value super (jcall 
"getName" super)) collect ", "))))
+      ,@(if has-interfaces
+            (list* '(:newline) '(:label "Implements Interfaces: ")
+                   (butlast (loop for i across (jclass-interfaces class) 
collect (list :value i (jcall "getName" i)) collect ", "))))
+      (:newline) (:label "Methods:") (:newline)
+      ,@(inspector-java-methods class)
+      ,@(if fields
+            (list*
+             '(:newline) '(:label "Fields:") '(:newline)
+             fields)))))
+
+(defmethod emacs-inspect ((object sys::structure-object))
+  (let ((structure-def (get (type-of object) 'system::structure-definition )))
+    `((:label "Type: ") (:value ,(type-of object)) (:newline)
+      (:label "Class: ") (:value ,(class-of object)) (:newline)
+      ,@(inspector-structure-slot-names-and-values object))))
+
+(defun inspector-structure-slot-names-and-values (structure)
+  (let ((structure-def (get (type-of structure) 
'system::structure-definition)))
+    `((:label "Slots: ") (:newline)
+      ,@(loop for slotdef in (sys::dd-slots structure-def)
+              for name = (sys::dsd-name slotdef)
+              for reader = (sys::dsd-reader slotdef)
+              for value = (eval `(,reader ,structure))
+              append
+              `("  " (:label ,(string-downcase (string name))) ": " (:value 
,value) (:newline))))))
+
+(defmethod emacs-inspect ((object sys::structure-class))
+  (let* ((name (jss::get-java-field object "name" t))
+         (def (get name  'system::structure-definition)))
+  `((:label "Class: ") (:value ,object) (:newline)
+    (:label "Raw defstruct definition: ") (:value ,def  ,(let ((*print-array* 
nil)) (prin1-to-string def))) (:newline)
+   ,@(parts-for-structure-def  name)
+    ;; copy-paste from slynk fancy inspector
+    ,@(when (slynk-mop:specializer-direct-methods object)
+        `((:label "It is used as a direct specializer in the following 
methods:")
+          (:newline)
+          ,@(loop
+              for method in (specializer-direct-methods object)
+              for method-spec = (slynk::method-for-inspect-value method)
+              collect "  "
+              collect `(:value ,method ,(string-downcase (string (car 
method-spec))))
+              collect `(:value ,method ,(format nil " (~{~a~^ ~})" (cdr 
method-spec)))
+              append (let ((method method))
+                       `(" " (:action "[remove]"
+                                      ,(lambda () (remove-method 
(slynk-mop::method-generic-function method) method)))))
+              collect '(:newline)
+              if (documentation method t)
+                collect "    Documentation: " and
+              collect (slynk::abbrev-doc  (documentation method t)) and
+              collect '(:newline)))))))
+
+(defun parts-for-structure-def-slot (def)
+  `((:label ,(string-downcase (sys::dsd-name def))) " reader: " (:value 
,(sys::dsd-reader def) ,(string-downcase (string (sys::dsdreader def))))
+    ", index: " (:value ,(sys::dsd-index def))
+    ,@(if (sys::dsd-initform def)
+          `(", initform: " (:value ,(sys::dsd-initform def))))
+    ,@(if (sys::dsd-read-only def)
+         '(", Read only"))))
+  
+(defun parts-for-structure-def (name)
+  (let ((structure-def (get name 'system::structure-definition )))
     (append
-     (if (gethash o *to-string-hashtable*)
-         (label-value-line "toString()" (gethash o *to-string-hashtable*))
-         `((:action "[compute toString()]" ,to-string) (:newline)))
-     (loop :for (label . value) :in (sys:inspected-parts o)
-      :appending (label-value-line label value)))))
+     (loop for accessor in '(dd-name dd-conc-name dd-default-constructor 
dd-constructors dd-copier dd-include dd-type
+                             dd-named dd-initial-offset dd-predicate 
dd-print-function dd-print-object
+                             dd-inherited-accessors)
+           for key = (intern (subseq (string accessor) 3) 'keyword)
+           for fsym = (find-symbol (string accessor) 'system)
+           for value = (eval `(,fsym ,structure-def))
+           append `((:label ,(string-capitalize (string key))) ": " (:value 
,value) (:newline)))
+     (let* ((direct (sys::dd-direct-slots structure-def) )
+           (all (sys::dd-slots structure-def))
+           (inherited (set-difference all direct)))
+     `((:label "Direct slots: ") (:newline)
+       ,@(loop for slotdef in direct  
+               append `("  " ,@(parts-for-structure-def-slot slotdef)
+                             (:newline)))
+       ,@(if inherited 
+             (append '((:label "Inherited slots: ") (:newline))
+                     (loop for slotdef in inherited  
+                           append `("  " (:label ,(string-downcase (string 
(sys::dsd-name slotdef))))
+                                         (:value ,slotdef "slot definition")
+                                         (:newline))))))))))
 
 ;;;; Multithreading
 
@@ -767,7 +1438,7 @@ part of *sysdep-pathnames* in slynk.loader.lisp.
               (incf *thread-id-counter*)))))
 
 (defimplementation find-thread (id)
-  (find id (all-threads) 
+  (find id (all-threads)
         :key (lambda (thread)
                (getf (gethash thread *thread-plists*) 'id))))
 
@@ -794,12 +1465,12 @@ part of *sysdep-pathnames* in slynk.loader.lisp.
   (member thread (all-threads)))
 
 (defimplementation interrupt-thread (thread fn)
-  (threads:interrupt-thread thread fn)) 
+  (threads:interrupt-thread thread fn))
 
 (defimplementation kill-thread (thread)
   (threads:destroy-thread thread))
 
-(defstruct mailbox 
+(defstruct mailbox
   (queue '()))
 
 (defun mailbox (thread)
@@ -812,7 +1483,7 @@ part of *sysdep-pathnames* in slynk.loader.lisp.
 (defimplementation send (thread message)
   (let ((mbox (mailbox thread)))
     (threads:synchronized-on mbox
-      (setf (mailbox-queue mbox) 
+      (setf (mailbox-queue mbox)
             (nconc (mailbox-queue mbox) (list message)))
       (threads:object-notify-all mbox))))
 
@@ -824,7 +1495,7 @@ part of *sysdep-pathnames* in slynk.loader.lisp.
      (threads:synchronized-on mbox
        (let* ((q (mailbox-queue mbox))
               (tail (member-if test q)))
-         (when tail 
+         (when tail
            (setf (mailbox-queue mbox) (nconc (ldiff q tail) (cdr tail)))
            (return (car tail)))
          (when (eq timeout t) (return (values nil t)))
@@ -832,7 +1503,31 @@ part of *sysdep-pathnames* in slynk.loader.lisp.
 
 (defimplementation quit-lisp ()
   (ext:exit))
+
+;; FIXME probably should be promoted to other lisps but I don't want to mess 
with them
+(defvar *inspector-print-case* *print-case*)
+
+(defimplementation call-with-syntax-hooks (fn)
+  (let ((*print-case* *inspector-print-case*))
+    (funcall fn)))
+
 ;;;
-#+#.(slynk-backend:with-symbol 'package-local-nicknames 'ext)
+#+#.(slynk/backend:with-symbol 'package-local-nicknames 'ext)
 (defimplementation package-local-nicknames (package)
   (ext:package-local-nicknames package))
+
+;; all the defimplentations aren't compiled. Compile them. Set their
+;; function name to be the same as the implementation name so
+;; meta-. works.
+
+#+abcl-introspect
+(eval-when (:load-toplevel :execute)
+  (loop for s in slynk-backend::*interface-functions*
+        for impl = (get s 'slynk-backend::implementation)
+        do (when (and impl (not (compiled-function-p impl)))
+             (let ((name (gensym)))
+               (compile name  impl)
+               (let ((compiled (symbol-function name)))
+                 (system::%set-lambda-name compiled (second (sys::lambda-name 
impl)))
+                 (setf (get s 'slynk-backend::implementation) compiled))))))
+



reply via email to

[Prev in Thread] Current Thread [Next in Thread]