John DeBord
John DeBord

Reputation: 705

Navigating to the definitions of `defun` and `defmacro` with slime/swank

Emacs version: 26.3
Slime version: 2.26.1


I start up Emacs.

I open up a simple .lisp file.

(defun testfn (x y)
  (+ x y))

(defmacro testmc (form)
  form
  `(list 1 2 3))

I place my cursor over the symbol defun and issue the keyboard-command M-. (slime-edit-definition).

This should bring me to the definition of defun.

But it doesn't.

It brings me here:

enter image description here

I place my cursor over the symbol defmacro and issue the keyboard-command M-. (slime-edit-definition).

This should bring me to the definition of defmacro.

But it doesn't.

It brings me here:

enter image description here

Why does it do this & how do I fix this

Upvotes: 0

Views: 306

Answers (2)

coredump
coredump

Reputation: 38789

Notice there is a warning in the REPL when trying to find the source of DEFUN:

WARNING: inconsistent 2 form-number-translations

You can replicate it yourself in the REPL:

CL-USER> (let ((slynk::*buffer-package* (find-package :cl))
               (slynk::*buffer-readtable* *readtable*))
          (slynk:find-definitions-for-emacs "DEFUN"))
WARNING: inconsistent 2 form-number-translations
(("(DEFMACRO DEFUN)"
  (:LOCATION (:FILE "/home/chris/data/src/sbcl/src/code/macros.lisp")
   (:POSITION 4140)
   (:SNIPPET "(setq doc nil)
    (let* (;; stuff shared between LAMBDA and INLINE-LAMBDA and NAMED-LAMBDA
           (lambda-guts `(,@decls (block ,(fun-name-block-name name) ,@forms)))
           (lambda `(lambda ,lambda-list ,@lambda-guts))
           (named-lambda `("))))

To find where the warning comes from, you could do as I did first and do a textual search on the repository, or you could use the following alternate method that works better, namely invoke the debugger on warnings:

(handler-bind ((warning (lambda (c) (invoke-debugger c))))
  (let ((slynk::*buffer-package* (find-package :cl))
        (slynk::*buffer-readtable* *readtable*))
    (slynk:find-definitions-for-emacs "DEFUN")))

This comes from SLYNK-SBCL::FORM-NUMBER-POSITION, and the interesting value in the debugger is the source location obtained from SBCL:

#<SB-INTROSPECT:DEFINITION-SOURCE {10369C50F3}>
--------------------
The object is a STRUCTURE-OBJECT of type SB-INTROSPECT:DEFINITION-SOURCE.
PATHNAME: #P"SYS:SRC;CODE;MACROS.LISP"
FORM-PATH: (5)
FORM-NUMBER: 89
CHARACTER-OFFSET: 3917
FILE-WRITE-DATE: 3825178034
PLIST: NIL
DESCRIPTION: NIL

It says the source is the fifth toplevel form in the file (which corresponds to the character offset), and from here, the FORM-NUMBER is the 89th form in a depth-first search walk of the form (this comes from the structure's docstring).

But, if I recompile the function FORM-NUMBER-POSITION with DEBUG set to 3, the toplevel form read at this position, TLF is NIL:

 1: (SLYNK-SBCL::FORM-NUMBER-POSITION #S(SB-INTROSPECT:DEFINITION-SOURCE :PATHNAME #P"SYS:SRC;CODE;MACROS.LISP" :FORM-PATH (5) :FORM-NUMBER 89 :CHARACTER-OFFSET 3917 :FILE-WRITE-DATE 3825178034 :PLIST NIL..
      Locals:
        DEFINITION-SOURCE = #S(SB-INTROSPECT:DEFINITION-SOURCE :PATHNAME #P"SYS:SRC;CODE;MACROS.LISP" :FORM-PATH (5) :FORM-NUMBER 89 :CHARACTER-OFFSET 3917 :FILE-WRITE-DATE 3825178034 :PLIST NIL :DESCRIPTION NIL)
        FORM-NUMBER = 89
        PATH-TABLE = #((0 0))
        POS-MAP = #<HASH-TABLE :TEST EQ :COUNT 126 {103B227EA3}>
        POS-MAP#1 = #<HASH-TABLE :TEST EQ :COUNT 126 {103B227EA3}>
        STREAM = #<SB-IMPL::STRING-INPUT-STREAM {7F3E0350D953}>
        TLF = NIL
        TLF#1 = NIL
        TLF-NUMBER = 5

In read-source-form, you can see that the form is being read inside a (ignore-errors (read ...)) form, which returns NIL in case of error. I tried calling (read ...) only but this somehow did not invoke the debugger, so I did the same thing as above and explicitly invoked it on any condition.

There is an error, namely that the package "SB-XC" does not exist, which is expected since, if I am not mistaken, this is a package that only exists during the compilation of SBCL itself.

I think you should contact the SBCL SLY developers and file a bug for this directly, they would certainly have a better idea of how to fix the behaviour (feel free to link to your question in addition to giving the usual details of the bug report).

Upvotes: 2

Francis King
Francis King

Reputation: 1732

I'm seeing pretty much what you're seeing.

Defun (line 280 of defboot.lisp) is a macro, which is defined in terms of defun-expander (line 230 of defboot.lisp) which is what you're seeing.

Whereas, defmacro takes you directly to its definition (line 15 of defmacro.lisp) which is what you're seeing.

It seems to be doing useful things.

I defined a new function 'addmore'

(defun addmore (x y z)
  (testfn x (testfn y z)))

I compiled it all, and M-. on 'addmore' takes me to the definition of testfn.

So I think it's all working.

Upvotes: 1

Related Questions