2

我想获取上次编写特定函数或宏定义的文件的名称,用于各种文档和测试目的?

在 PJB 在#CommonLisp (IRC.LIBERA.CHAT) 上的帮助下,我发布了一个对我来说效果很好的答案,但会接受任何提供不依赖 SWANK 的便携式解决方案的答案或提供有关如何在 LispWorks、ACL 等其他 IDE 中实现相同的功能。

4

2 回答 2

4

如果您寻求的是一种可移植的解决方案——一种用可移植 CL 编写的解决方案——那么答案就是定义用于定义表单的包装器,然后使用包装器。

(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))

在现实生活中,您define-function defun当然会调用define-variableetc,然后为 CL 构建一个管道包,该包导出所有 CL 符号,同时用这些符号替换定义形式。

如果您寻求的是一种可移植的解决方案,即它导出一些标准接口但具有不同的实现相关的后端,那么可能看看 SLY 或 SWANK 做什么是一个好的开始。在 LW 的情况下,您可能希望后端使用 DSPEC,这是它处理位置信息的方式:

> (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))
于 2021-10-22T13:14:31.977 回答
4

#CommonLisp (IRC.LIBERA.CHAT) 上的 PJB 提供了极大的帮助并提供了以下答案(我已经解释过,所以任何错误都归我所有):

首先,CL 是一个 lisp-2(实际上是 lisp-∞),因此可能没有一个单一的定义附加到一个符号上。例如,foo下面提到的是哪个?

(deftype foo () (member foo))

(defvar foo 'foo)

(defun foo () foo)

此外,作为一个例子,符号可以在 REPL 中定义(没有关联的文件名),所以这不是一个可以在不假设意图的情况下直接回答的问题。

现在,当 的行为M-.满足您的要求时,您可以在 slime/swank 中查看实现特定 API 的用途。

这应该指向您swank:find-definition-for-emacs,这可能是您所追求的:

(swank:find-definitions-for-emacs "foo") #| -->

(("#'foo"
 (:location (:file "/private/tmp/foo.lisp")
 (:position 50)
 (:snippet "(defun foo () foo)")))
 
 ("(type foo)"
 (:location (:file "/private/tmp/foo.lisp")
 (:position 1)
 (:snippet "(deftype foo () '(member foo))")))
 
 ("(variable foo)"
 (:location (:file "/private/tmp/foo.lisp")
 (:position 32)
 (:snippet "(defvar foo 'foo)")))) 

如果您想依赖上述内容,请确保将其swank作为依赖项加载到您的文件中。.asd

编辑:我还发现以下内容非常有用(并且 swank 对于大多数实现都有类似的文件,所以只需浏览每个文件以查看它们的等价物):

https://github.com/slime/slime/blob/68c58c0194ff03cd147fcec99f0ee90ba9178875/swank/sbcl.lisp#L811

(sb-introspect:find-definition-sources-by-name name type)假设您使用的是 SBCL,函数调用(名称是符号,类型是关键字,例如 :function - 请参阅上面的链接)返回存储定义的文件。更多 (SBCL) 细节也在:

https://github.com/sbcl/sbcl/blob/master/contrib/sb-introspect/introspect.lisp

于 2021-10-22T11:19:26.383 回答