Comment évaluer le code Elisp contenu dans une chaîne?

21

La question dit à peu près tout: j'ai une chaîne contenant le code source pour une expression Elisp valide, et je voudrais l'évaluer.

(En Python, par exemple, l'expression est eval("1 - 2 + 3")évaluée à 2.)

kjo
la source
2
Remarque, (calc-eval "1 - 2 + 3")convient mieux à votre exemple python même si ce n'est pas elisp valide. Si vous n'avez pas encore besoin du calcpaquet, vous devez le charger auparavant avec (require 'calc). (Je sais que cela ne répond pas à votre question. C'est pourquoi il est formulé comme un commentaire.)
Tobias

Réponses:

24

L'évaluation d'une chaîne de code elisp est un processus en deux étapes: vous devez analyser la chaîne en utilisant read-from-stringpuis évaluer l'expression Lisp résultante avec eval.

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

Évalue maintenant (my-eval-string "(+ 1 2)")à 3.

Éditer:

Comme l'a souligné @lunaryorn , read-from-string lit uniquement la première expression , donc cela devrait être mieux:

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

Modifier 2:

Pour évaluer le code elisp pour les effets secondaires, on pourrait également utiliser with-temp-bufferet eval-buffer( eval-bufferrenvoie toujours 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
la source
with-temp-bufferest loin d'être idéal car il gâchera tous les appels liés au tampon, par exemple buffer-file-name...
Ha-Duong Nguyen
5

La réponse de Constantine est correcte.

Juste pour apporter une légère modification:

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

Le dernier formulaire renvoie la liste (1 2 3 4).

Tobias
la source