Como avaliar o código Elisp contido em uma string?

21

A pergunta praticamente diz tudo: eu tenho uma string contendo o código-fonte para uma expressão válida do Elisp e gostaria de avaliá-la.

(Em Python, por exemplo, a expressão é eval("1 - 2 + 3")avaliada como 2.)

kjo
fonte
2
Observe que ele (calc-eval "1 - 2 + 3")se encaixa melhor no seu exemplo de python, mesmo que esse elisp não seja válido. Se você ainda não precisa do calcpacote, precisa carregá-lo antes (require 'calc). (Eu sei que isso não responder à sua pergunta Por isso, é formulado como comentário..)
Tobias

Respostas:

24

Avaliar uma sequência de códigos elisp é um processo de dois estágios: você precisa analisar a sequência usando read-from-stringe, em seguida, avaliar a expressão Lisp resultante com eval.

(defun my-eval-string (string)
  "Evaluate elisp code stored in a string."
  (eval (car (read-from-string string))))

Agora (my-eval-string "(+ 1 2)")avalia como 3.

Editar:

Conforme apontado por @lunaryorn , read-from-string lê apenas a primeira expressão , portanto deve ser melhor:

(defun my-eval-string (string)
  (eval (car (read-from-string (format "(progn %s)" string)))))

Edição 2:

Para avaliar o código elisp para efeitos colaterais, também se pode usar with-temp-buffere eval-buffer( eval-buffersempre retorna nil).

(defun my-eval-string-for-side-effects (string)
  "Evaluate a string of elisp code for side effects."
  (with-temp-buffer
    (insert string)
    (eval-buffer)))

(my-eval-string-for-side-effects "(message \"hello!\")")
Constantine
fonte
with-temp-bufferé inferior a ideal porque vai mexer com todas as chamadas relacionadas com o tampão, por exemplo buffer-file-name, ...
Ha-Duong Nguyen
5

A resposta de Constantino está bem.

Apenas para fornecer uma ligeira modificação:

(defun my-eval-string (str)
  "Read and evaluate all forms in str.
Return the results of all forms as a list."
  (let ((next 0)
        ret)
    (condition-case err
        (while t
          (setq ret (cons (funcall (lambda (ret)
                                     (setq next (cdr ret))
                                     (eval (car ret)))
                                   (read-from-string str next))
                          ret)))
      (end-of-file))
    (nreverse ret)))

(my-eval-string "1 2 3 (+ 3 1)")

O último formulário retorna a lista (1 2 3 4).

Tobias
fonte