Dependencies 收集文件中的符号

Dependencies 收集文件中的符号,dependencies,common-lisp,symbols,Dependencies,Common Lisp,Symbols,由于程序的各个文件是按顺序编译和加载的,有没有办法找出在特定文件中引用了(即,插入或引用)哪些符号?(为了简单起见,假设使用单个软件包。) 例如,如果程序的前两个文件已成功加载,如何将第二个文件中新插入的符号以及依赖于第一个文件中定义的第二个文件的符号收集到列表中 函数是否可以使用符号提取在文件加载的每个步骤中创建的符号?(或者,是否可以单独使用公共Lisp读取器从文件中的每个表单获取符号?) (注:更广泛的目标是确定任何两个文件之间是否存在依赖关系。)如果不在读取器中执行复杂的操作,您就无法轻

由于程序的各个文件是按顺序编译和加载的,有没有办法找出在特定文件中引用了(即,插入或引用)哪些符号?(为了简单起见,假设使用单个软件包。)

例如,如果程序的前两个文件已成功加载,如何将第二个文件中新插入的符号以及依赖于第一个文件中定义的第二个文件的符号收集到列表中

函数
是否可以使用符号
提取在文件加载的每个步骤中创建的符号?(或者,是否可以单独使用公共Lisp读取器从文件中的每个表单获取符号?)


(注:更广泛的目标是确定任何两个文件之间是否存在依赖关系。)

如果不在读取器中执行复杂的操作,您就无法轻松找到先前存在的符号(您必须实现自己的、兼容的符号读取器)(但请参见下文)

您可以了解创建了哪些新符号

隐藏符号
隐藏符号,并且
新符号
返回不在隐藏中的符号列表:

(defun stash-symbols (&key (packages (list-all-packages))
                           (into (make-hash-table))
                           (external-only nil))
  (dolist (p packages into)
    (if external-only
        (do-external-symbols (s p)
          (setf (gethash s into) s))
      (do-symbols (s p)
        (setf (gethash s into) s)))))

(defun new-symbols (stash &key (packages (list-all-packages))
                          (external-only nil))
  (let ((news '()))
    (dolist (p packages)
      (if external-only
          (do-external-symbols (s p)
            (unless (eq (gethash s stash) s)
              (push s news)))
          (do-symbols (s p)
            (unless (eq (gethash s stash) s)
              (push s news)))))
    news))
现在
load/comparing
隐藏、加载文件并报告新符号。请注意,加载文件可以创建包(事实上,更智能的版本会报告先前存在的包中的新符号列表以及新包列表):这很容易做到,但我现在太懒了

(defun load/comparing (file &key (packages nil packages-p)
                            (external-only nil))
  ;; Note the list of packages can easily change during LOAD!
  (let ((stash (stash-symbols :packages (if packages-p
                                            packages
                                          (list-all-packages))
                              :external-only external-only)))
    (values (load file)
            (new-symbols stash
                         :packages (if packages-p
                                       packages
                                     (list-all-packages))
                         :external-only external-only))))
试图找出加载文件中所有符号的一种方法是尝试编写一个函数,该函数只是假装加载一个文件,实际上只是读取它。这很难做到正确。这里有一个函数,它肯定没有做到正确,但它至少在包
表单中“听到”
,因此它可能会工作k在许多有用的情况下(但要注意
eval when
,而且
(defpackage…)(in-package…
将注定失败,这可能可以通过首先真正加载文件来创建包来解决):

现在呢

(defun extract-interesting-symbols (forms &key (into (make-hash-table))
                                          (filter nil filterp))
  ;; Find interesting symbols in FORMS.  NIL is never interesting
  ;; (sorry).
  (labels ((extract (thing)
             (typecase thing
               (null nil)
               (symbol
                (when (or (not filterp)
                          (funcall filter thing))
                  (incf (gethash thing into 0))))
               (cons
                (extract (car thing))
                (extract (cdr thing))))))
    (extract forms)
    into))
因此,现在(使用):


您可以从结果中看到,该文件中有一个
eval when
(实际上还有一个
defpackage
),但这并不重要,因为我已经加载了它,所以它的工作就完成了。

我最初只是想用
do symbols
在某个时间点对包中的所有符号进行清点。然后在加载该包中的文件后,再次清点并设置两者之间的差异。这看起来像是您手工制作的解决方案n是相似的。你能概述一下区别吗?这样我就能理解为什么直截了当的方法会有问题。感谢你在这方面的工作。问题是,比较包状态只会显示新的符号:你想要的是仅被引用的符号。
(defun extract-interesting-symbols (forms &key (into (make-hash-table))
                                          (filter nil filterp))
  ;; Find interesting symbols in FORMS.  NIL is never interesting
  ;; (sorry).
  (labels ((extract (thing)
             (typecase thing
               (null nil)
               (symbol
                (when (or (not filterp)
                          (funcall filter thing))
                  (incf (gethash thing into 0))))
               (cons
                (extract (car thing))
                (extract (cdr thing))))))
    (extract forms)
    into))
> (collecting (maphash (lambda (s c) (collect (cons s c)))
                       (extract-interesting-symbols
                        (try-to-pretend-to-load-file 
                         "binding.lisp"))))
((org.tfeb.hax.binding::what . 2)
 (:compile-toplevel . 1)
 (org.tfeb.hax.binding::expanded . 4)
 (labels . 6)
 (org.tfeb.hax.binding::form/expansion . 2)
 (:load-toplevel . 1)
 (:test . 2)
 (org.tfeb.hax.binding::a . 16)
 (ecase . 1)
 (&rest . 4)
 (:org.tfeb.hax.collecting . 2)
 (org.tfeb.hax.binding::b . 20)
 (quote . 31)
 (equal . 1)
 (collecting . 1)
 (org.tfeb.hax.binding::f . 4)
 (consp . 1)
 (first . 14)
 ...)