¿Cómo evaluar el código Elisp contenido en una cadena?

21

La pregunta lo dice todo: tengo una cadena que contiene el código fuente para una expresión válida de Elisp, y me gustaría evaluarla.

(En Python, por ejemplo, la expresión se eval("1 - 2 + 3")evalúa como 2.)

kjo
fuente
2
Tenga en cuenta que se (calc-eval "1 - 2 + 3")ajusta mejor a su ejemplo de Python incluso si esto no es válido elisp. Si aún no necesita el calcpaquete, debe cargarlo antes (require 'calc). (Sé que esto no responde a su pregunta. Por lo tanto, está formulado como comentario.)
Tobias

Respuestas:

24

Evaluar una cadena de código elisp es un proceso de dos etapas: debe analizar la cadena usando read-from-stringy luego evaluar la expresión de Lisp resultante con eval.

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

Ahora (my-eval-string "(+ 1 2)")evalúa a 3.

Editar:

Como señaló @lunaryorn , solo read-from-string lee la primera expresión , por lo que esto debería ser mejor:

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

Edición 2:

Para evaluar el código elisp para los efectos secundarios, también se podría usar with-temp-buffery eval-buffer( eval-buffersiempre se devuelve 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!\")")
Constantina
fuente
with-temp-bufferes menos que ideal porque arruinará todas las llamadas relacionadas con el búfer, por ejemplo buffer-file-name, ...
Ha-Duong Nguyen
5

La respuesta de Constantino está bien.

Solo para proporcionar una ligera modificación:

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

El último formulario devuelve la lista (1 2 3 4).

Tobias
fuente