Risposta aggiornata con ricerca del tempo di espansione:
Nella mia risposta originale ho detto che potrebbe esserci un modo per farlo in fase di espansione / compilazione anziché in fase di esecuzione per fornire prestazioni migliori e alla fine l'ho implementato oggi mentre lavoravo sulla mia risposta per questa domanda: Come posso determinare quale funzione era chiamato interattivamente nello stack?
Ecco una funzione che produce tutti i frame di backtrace correnti
(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)))
Usandolo in una macro possiamo cercare lo stack di espansione per vedere quale definizione di funzione viene espansa in quel momento e mettere quel valore nel codice.
Ecco la funzione per fare l'espansione:
(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)))))))
Qui è in azione.
(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'"
Risposta originale:
Puoi usare backtrace-frame
per cercare lo stack finché non vedi un frame che rappresenta una chiamata di funzione diretta e ne ottieni il nome.
(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
Qui sto eseguendo la ricerca del nome della funzione in fase di runtime sebbene sia probabilmente possibile implementarlo in una macro che si espande direttamente nel simbolo della funzione che sarebbe più performante per le chiamate ripetute e l'elisp compilato.
Ho trovato queste informazioni mentre cercavo di scrivere una sorta di logger di chiamate di funzione per elisp che può essere trovato qui nella sua forma incompleta, ma potrebbe esserti utile. https://github.com/jordonbiondo/call-log