Обновленный ответ с поиском по времени расширения:
В своем первоначальном ответе я сказал, что может быть способ сделать это во время развертывания / компиляции вместо времени выполнения, чтобы повысить производительность, и я, наконец, реализовал это сегодня, работая над своим ответом на этот вопрос: как определить, какая функция была интерактивно вызывается в стеке?
Вот функция, которая выдает все текущие кадры обратного следа
(defun call-stack ()
"Return the current call stack frames."
(let ((frames)
(frame)
(index 5))
(while (setq frame (backtrace-frame index))
(push frame frames)
(incf index))
(remove-if-not 'car frames)))
Используя это в макросе, мы можем найти стек расширения, чтобы увидеть, какое определение функции расширяется в данный момент, и поместить это значение прямо в код.
Вот функция для расширения:
(defmacro compile-time-function-name ()
"Get the name of calling function at expansion time."
(symbol-name
(cadadr
(third
(find-if (lambda (frame) (ignore-errors (equal (car (third frame)) 'defalias)))
(reverse (call-stack)))))))
Вот оно в действии.
(defun my-test-function ()
(message "This function is named '%s'" (compile-time-function-name)))
(symbol-function 'my-test-function)
;; you can see the function body contains the name, not a lookup
(lambda nil (message "This function is named '%s'" "my-test-function"))
(my-test-function)
;; results in:
"This function is named 'my-test-function'"
Оригинальный ответ:
Вы можете использовать backtrace-frame
поиск стека, пока не увидите фрейм, представляющий прямой вызов функции, и не получите имя из этого.
(defun get-current-func-name ()
"Get the symbol of the function this function is called from."
;; 5 is the magic number that makes us look
;; above this function
(let* ((index 5)
(frame (backtrace-frame index)))
;; from what I can tell, top level function call frames
;; start with t and the second value is the symbol of the function
(while (not (equal t (first frame)))
(setq frame (backtrace-frame (incf index))))
(second frame)))
(defun my-function ()
;; here's the call inside my-function
(when t (progn (or (and (get-current-func-name))))))
(defun my-other-function ()
;; we should expect the return value of this function
;; to be the return value of my-function which is the
;; symbol my-function
(my-function))
(my-other-function) ;; => 'my-function
Здесь я делаю поиск имени функции во время выполнения, хотя, вероятно, возможно реализовать это в макросе, который расширяется непосредственно в символ функции, который был бы более производительным для повторных вызовов и скомпилированного elisp.
Я нашел эту информацию, пытаясь написать своего рода журнал вызовов функций для elisp, который можно найти здесь в его неполной форме, но он может быть полезен для вас. https://github.com/jordonbiondo/call-log