Skip to content

Instantly share code, notes, and snippets.

@ashok-khanna
Created October 22, 2021 17:41
Show Gist options
  • Save ashok-khanna/a14fb3c55d05753b4f49ebe8d6a5ad1f to your computer and use it in GitHub Desktop.
Save ashok-khanna/a14fb3c55d05753b4f49ebe8d6a5ad1f to your computer and use it in GitHub Desktop.
How to get file name of a defined function?

Courtesy of ignis volens on SO: https://stackoverflow.com/questions/69675964/how-to-get-the-filename-where-a-function-is-defined-in-common-lisp/69677540#69677540

If what you seek is a portable solution – one that is written in portable CL – then the answer to that is to define wrappers for defining forms and then use the wrappers.

(defvar *flocs* (make-hash-table :test #'equal))

(defgeneric function-location (f/name)
  (:method ((name t))
   (values (gethash name *flocs* nil) t))
  (:method ((f function))
   (multiple-value-bind (le cp nm) (function-lambda-expression f)
     (declare (ignore le cp))
     (if nm
         (function-location nm)
       (values nil nil)))))

(defmacro define-function (f args &body doc/decls/forms)
  (when (or *load-pathname* *compile-file-pathname*)
    ;; Prefer *load-pathname*
    (setf (gethash f *flocs*) (or *load-pathname* *compile-file-pathname*)))
  `(defun ,f ,args ,@doc/decls/forms))

In real life you'd call define-function defun of course, and similarly with define-variable etc, and then construct a conduit package for CL which exported all the CL symbols while replacing the defining forms with these ones.

If what you seek is a portable solution in the sense that it exports some standard interface but has varying implementation-dependent backends, then probably looking at what SLY or SWANK do is a good start. In the case of LW you would want the backend to use DSPECs which are how it deals with location information:

> (dspec:dspec-definition-locations '(defun foo))
(((defun foo) :listener))

> (dspec:dspec-definition-locations '(defun needs))
(((defmacro needs)
  #P"..."))

> (defclass foo () ())
#<standard-class foo 402000B763>

> (dspec:name-definition-locations dspec:*dspec-classes* 'foo)
(((defclass foo) :listener) ((defun foo) :listener))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment