Как оценить код Elisp, содержащийся в строке?

21

Вопрос в значительной степени говорит сам за себя: у меня есть строка, содержащая исходный код для допустимого выражения Elisp, и я хотел бы оценить его.

(Например, в Python выражение eval("1 - 2 + 3")оценивается как 2.)

KJo
источник
2
Обратите внимание, (calc-eval "1 - 2 + 3")лучше подходит для вашего примера с Python, даже если это недопустимый elisp. Если вам пока не требуется calcпакет, вам необходимо загрузить его до (require 'calc). (Я знаю, что это не отвечает на ваш вопрос. Следовательно, это сформулировано как комментарий.)
Тобиас

Ответы:

24

Оценка строки кода elisp - это двухэтапный процесс: вам нужно проанализировать строку, используя, read-from-stringа затем оценить полученное выражение Lisp с помощью eval.

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

Теперь (my-eval-string "(+ 1 2)")оценивает 3.

Редактировать:

Как указывает @lunaryorn , read-from-string читает только первое выражение , так что это должно быть лучше:

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

Изменить 2:

Для оценки кода elisp для побочных эффектов можно также использовать with-temp-bufferи eval-buffer( eval-bufferвсегда возвращает 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!\")")
Константин
источник
with-temp-bufferменее чем идеален, потому что он испортит все вызовы, связанные с буфером, например buffer-file-name, ...
Ха-Дуонг Нгуен,
5

Ответ Константина в порядке.

Просто чтобы предоставить небольшую модификацию:

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

Последняя форма возвращает список (1 2 3 4).

Тобиас
источник