As funções podem acessar seus nomes?

25

Em C, existe a variável mágica __func__que contém o nome da função atual. No Bash, existe uma matriz FUNCNAMEcontendo os nomes de todas as funções na pilha de chamada !!!

Existe algo semelhante no Emacs Lisp? Ou alguma maneira simples de uma função ter acesso ao seu nome?

Não encontrei nenhuma resposta no manual Emacs Lisp (capítulo 12 sobre Funções ou índice de variáveis ​​e funções e ..)

phs
fonte
2
Para que você realmente precisa disso?
lunaryorn
11
Não é exatamente uma variável mágica - é uma definição de pré-processador inserida por alguns compiladores.
Sean Allred

Respostas:

6

Para funções interativas, ou seja, comandos, você pode usar a variável this-commandou mais seguro real-this-command. A diferença é que, quando você escreve suas próprias funções, pode alterar explicitamente o valor de this-command. Isso é feito principalmente para executar truques last-commandrelacionados a comandos repetidos. Você não deve (não pode?) Fazer isso com real-this-command. Será sempre o nome do comando atual.

Não conheço um equivalente para funções não interativas.

Tyler
fonte
3
É importante observar isso this-commande real-last-commandnão é nada parecido __func__. Por exemplo, se o comando A chamar o comando B que o imprime this-command, imprimirá o comando A, e não B, também isso não funciona para as funções.
Jordon Biondo
11
@JordonBiondo concordou. Eu notei que não funciona para funções. O phs não nos deu seu contexto, então imaginei que isso poderia ser bom o suficiente para sua aplicação. Sua resposta é mais robusta, sem dúvida.
Tyler
22

Resposta atualizada com pesquisa de tempo de expansão:

Eu disse na minha resposta original que pode haver uma maneira de fazer isso no tempo de expansão / compilação, em vez do tempo de execução, para oferecer melhor desempenho e finalmente o implementei hoje, enquanto trabalhava na minha resposta para esta pergunta: Como posso determinar qual função foi chamado interativamente na pilha?

Aqui está uma função que gera todos os quadros de backtrace atuais

(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)))

Usando isso em uma macro, podemos procurar a pilha de expansão para ver qual definição de função está sendo expandida no momento e colocar esse valor no código.

Aqui está a função para fazer a expansão:

(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)))))))

Aqui está em ação.

(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'"

Resposta original:

Você pode usar backtrace-framepara procurar a pilha até ver o quadro que representa uma chamada de função direta e obter o nome disso.

(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

Aqui, estou pesquisando o nome da função em tempo de execução, embora provavelmente seja possível implementá-la em uma macro que se expanda diretamente no símbolo da função, que teria melhor desempenho para chamadas repetidas e elisp compilado.

Encontrei essas informações ao tentar escrever um tipo de registrador de chamadas de função para elisp, que pode ser encontrado aqui em sua forma incompleta, mas pode ser útil para você. https://github.com/jordonbiondo/call-log

Jordon Biondo
fonte
Obrigado pelo código. Isso resolve meu problema e o aceitarei em alguns dias, a menos que alguém nos dê algum tipo de variável "current-function-name" que faz parte do depurador que você sugere.
Phs #
A propósito, ele não parece funcionar quando a defuné delimitado por eval-and-compile, ou seja, ele retorna nil.
Alexander Shukaev