【问题标题】:Elisp: make symbol-function return the source?Elisp:让符号函数返回源?
【发布时间】:2014-03-08 02:42:47
【问题描述】:

设置如下:

(defun square (x)
  (* x x))
;; square
(symbol-function 'square)
;; (lambda (x) (* x x))
(byte-compile 'square)
;; #[(x) "\211_\207" [x] 2]
(symbol-function 'square)
;; #[(x) "\211_\207" [x] 2]

square 被字节编译后,有没有办法获取源代码(lambda (x) (* x x))

我能想到的两个用途是内联当前函数调用 并进行调试步骤。

我尝试使用find-definition-noselect 来获取源代码, 但我想知道是否有更好的方法,因为它有时会引发

(error "Don't know where ... is defined")

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    Emacs 跟踪在哪个 file 中定义了哪个函数 name(此信息保存在 load-history 中)。为了找到定义,Emacs 在load-history 中查找,如果函数在其中列出,它会查找相应的源文件,然后在该文件中查找看起来可能是函数定义的内容(使用正则表达式)。这就是find-definition-noselect 所做的。

    至于源代码,一般 Emacs 不会保留源代码定义。如果您使用cl-defsubst 定义函数,则源会保留,否则不会。对于 Edebugging,拥有源代码无论如何都无济于事(因为 Edebug 不仅需要源代码,还需要每个子表达式的精确位置);对于简单的调试,也不需要源代码(您总是可以单击函数的名称跳转到源代码);也不需要内联源代码(字节编译器确实可以在源代码级别内联,但它也可以在字节代码级别内联)。

    【讨论】:

      【解决方案2】:

      没有办法获取函数对象的来源。字节编译不是单射函数,所以你不能恢复它。即使不考虑宏扩展,也没有从操作码到 Lisp 表达式的直接映射。

      无论如何,我没有看到这方面的用例。

      调试

      要进入调试函数,请导航到其定义(即find-definition)并检测用于调试的定义(例如使用 edebug)。这是合理调试 Emacs Lisp 函数的唯一方法。您不能使用函数单元格的内容进行调试,因为它受宏扩展的影响。

      因此,函数单元格可能看起来与实际定义完全不同。如果您在函数单元格中发现错误,您将很难在实际函数定义中找到相同的错误。

      内联

      对于内联,使用宏或defsubst 在 Emacs Lisp 中定义内联函数。但是,请注意不要意外地在库的公共接口上公开这些,因为编译时内联函数会对库施加编译时依赖性,因此需要为库的每个版本重新编译依赖库。而且由于 package.el 还不支持,宏和替换很容易造成破坏。

      【讨论】:

      • 您误解了内联部分。我的意思是内联扩展,即将源代码中的 (square 5) 替换为 (* 5 5)。调试也是如此:在上述情况下,我想跳转到square 的定义并将arg 设置为顶层5。没有错。我不喜欢edebug,因为它使源只读。我更喜欢在调试时编写代码。
      猜你喜欢
      • 1970-01-01
      • 2013-05-09
      • 1970-01-01
      • 1970-01-01
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多