Wie kann man den in einem String enthaltenen Elisp-Code auswerten?

21

Die Frage sagt eigentlich schon alles: Ich habe einen String, der den Quellcode für einen gültigen Elisp-Ausdruck enthält, und ich würde ihn gerne auswerten.

(In Python wird der Ausdruck beispielsweise eval("1 - 2 + 3")zu 2 ausgewertet.)

kjo
quelle
2
Beachten Sie, dass (calc-eval "1 - 2 + 3")Ihr Python-Beispiel besser passt, auch wenn dies kein gültiges elisp ist. Wenn Sie das calcPaket noch nicht benötigen , müssen Sie es vorher mit laden (require 'calc). (Ich weiß, dass dies Ihre Frage nicht beantwortet. Daher wird es als Kommentar formuliert.)
Tobias

Antworten:

24

Das Auswerten einer Zeichenfolge aus Elisp-Code erfolgt in zwei Schritten: Sie müssen die Zeichenfolge mit analysieren read-from-stringund dann den resultierenden Lisp-Ausdruck mit auswerten eval.

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

Jetzt (my-eval-string "(+ 1 2)")auswertet zu 3.

Bearbeiten:

Liest , wie von @lunaryorn hervorgehoben , read-from-string nur den ersten Ausdruck , daher sollte dies besser sein:

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

Bearbeiten 2:

Um den Elisp-Code auf Nebenwirkungen zu untersuchen, kann man auch with-temp-bufferund verwenden eval-buffer( eval-bufferimmer zurück 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!\")")
Konstantin
quelle
with-temp-bufferist weniger als ideal, weil es mit allen pufferbezogenen Anrufen durcheinander kommt, zB buffer-file-name...
Ha-Duong Nguyen
5

Die Antwort von Konstantin ist in Ordnung.

Nur um eine kleine Änderung vorzusehen:

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

Das letzte Formular gibt die Liste zurück (1 2 3 4).

Tobias
quelle