Jak ocenić kod Elisp zawarty w ciągu?

21

Pytanie w zasadzie mówi wszystko: mam ciąg znaków zawierający kod źródłowy prawidłowego wyrażenia Elisp i chciałbym go ocenić.

(Na przykład w Pythonie wyrażenie ma eval("1 - 2 + 3")wartość 2.)

kjo
źródło
2
Uwaga: (calc-eval "1 - 2 + 3")lepiej pasuje do twojego przykładu w python, nawet jeśli nie jest to poprawny elisp. Jeśli nie potrzebujesz jeszcze calcpakietu, musisz go wcześniej załadować (require 'calc). (Wiem, że to nie odpowiada na twoje pytanie. Stąd jest sformułowane jako komentarz.)
Tobias

Odpowiedzi:

24

Ocena ciągu kodu elisp jest procesem dwuetapowym: musisz go przeanalizować za pomocą, read-from-stringa następnie ocenić wynikowe wyrażenie Lisp za pomocą eval.

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

Teraz (my-eval-string "(+ 1 2)")ocenia na 3.

Edytować:

Jak wskazał @lunaryorn , read-from-string czyta tylko pierwsze wyrażenie , więc powinno być lepiej:

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

Edycja 2:

Aby ocenić kod elisp dla skutków ubocznych, można również użyć with-temp-bufferi eval-buffer( eval-bufferzawsze zwraca 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!\")")
Konstantyn
źródło
with-temp-bufferjest mniej niż idealny, ponieważ zepsuje wszystkie połączenia związane z buforami, np. buffer-file-name...
Ha-Duong Nguyen
5

Odpowiedź Konstantyna jest w porządku.

Wystarczy wprowadzić drobną modyfikację:

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

Ostatni formularz zwraca listę (1 2 3 4).

Tobiasz
źródło