Оновлена відповідь із пошуком часу розширення:
У своїй оригінальній відповіді я сказав, що може бути спосіб зробити це під час розширення / компіляції замість часу запуску, щоб забезпечити кращу продуктивність, і я нарешті це реалізував сьогодні, працюючи над своєю відповіддю на це питання: Як я можу визначити, яка функція була називається інтерактивно в стеку?
Ось функція, яка дає всі поточні кадри відтворення
(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