Bagaimana cara mengevaluasi kode Elisp yang terkandung dalam string?

21

Pertanyaannya cukup banyak mengatakan semuanya: Saya memiliki string yang berisi kode sumber untuk ekspresi Elisp yang valid, dan saya ingin mengevaluasinya.

(Dalam Python, misalnya, ekspresi eval("1 - 2 + 3")dievaluasi menjadi 2.)

kjo
sumber
2
Catatan, (calc-eval "1 - 2 + 3")cocok dengan contoh python Anda lebih baik bahkan jika ini bukan elisp yang valid. Jika Anda belum membutuhkan calcpaket tersebut, Anda harus memuatnya sebelumnya dengan (require 'calc). (Saya tahu ini tidak menjawab pertanyaan Anda. Oleh karena itu, ini dirumuskan sebagai komentar.)
Tobias

Jawaban:

24

Mengevaluasi string kode elisp adalah proses dua tahap: Anda perlu menguraikan string menggunakan read-from-stringdan kemudian mengevaluasi ekspresi Lisp yang dihasilkan dengan eval.

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

Sekarang (my-eval-string "(+ 1 2)")dievaluasi menjadi 3.

Edit:

Seperti yang ditunjukkan oleh @lunaryorn , read-from-string membaca ekspresi pertama saja , jadi ini seharusnya lebih baik:

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

Edit 2:

Untuk mengevaluasi kode elisp untuk efek samping, seseorang juga dapat menggunakan with-temp-bufferdan eval-buffer( eval-bufferselalu mengembalikan 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
sumber
with-temp-bufferkurang ideal karena akan mengacaukan semua panggilan yang berhubungan dengan penyangga, misalnya buffer-file-name, ...
Ha-Duong Nguyen
5

Jawaban Constantine baik-baik saja.

Hanya untuk memberikan sedikit modifikasi:

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

Bentuk terakhir mengembalikan daftar (1 2 3 4).

Tobias
sumber