Réponse mise à jour avec recherche de temps d'extension:
J'ai dit dans ma réponse d'origine qu'il pouvait y avoir un moyen de le faire au moment de l'expansion / de la compilation au lieu de l'exécution pour donner de meilleures performances et j'ai finalement implémenté cela aujourd'hui tout en travaillant sur ma réponse à cette question: comment puis-je déterminer quelle fonction était appelé de manière interactive dans la pile?
Voici une fonction qui produit toutes les trames de trace actuelles
(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)))
En utilisant cela dans une macro, nous pouvons rechercher la pile d'expansion pour voir quelle définition de fonction est développée à ce moment-là et mettre cette valeur directement dans le code.
Voici la fonction pour faire l'expansion:
(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)))))))
Le voici en action.
(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'"
Réponse originale:
Vous pouvez utiliser backtrace-frame
pour rechercher la pile jusqu'à ce que vous voyiez un cadre qui représente un appel de fonction direct et obtenez le nom de cela.
(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
Ici, je fais la recherche du nom de la fonction lors de l'exécution, mais il est probablement possible de l'implémenter dans une macro qui se développe directement dans le symbole de la fonction, ce qui serait plus performant pour les appels répétés et compilés elisp.
J'ai trouvé ces informations en essayant d'écrire une sorte d'enregistreur d'appels de fonction pour elisp qui peut être trouvé ici sous sa forme incomplète, mais cela pourrait vous être utile. https://github.com/jordonbiondo/call-log