Hello all, Currently, eval macros need to quote their arguments:
#+macro: identity (eval "$1") This means: 1. Users need to remember to put quotes around $n all the time 2. It’s impossible to pass arguments with a " character to a macro The attached patch changes the behavior of eval macro arguments so that $1 etc. expand to the argument with quotation marks. That is, the following is now the correct way to write a macro (note lack of "s): #+macro: identity (eval $1) This solves the above problems but: 1. breaks backwards compatibility of eval macros, since the with-quotes version is now incorrect 2. disables macros like the following, where the macro arguments are interpreted as lisp symbols: #+macro: funcall2 (eval ($1 $2 $3)) {{{funcall2(setq,org-export-with-date,nil)}}} For 1, I can add a check for "$n" constructs (including quotes) to org-lint and/or org-macro, to detect the backwards compatibility error. I believe that macros like in 2 are rather perverse: macro arguments are most similar to strings, not symbols or arbitrary pieces of lisp. (For arbitrary lisp evaluation, there’s babel.) Nonetheless, such macros can be recreated explicitly in the new system using eval+read and string interpolation: #+macro: funcall2 (eval (eval (read (format "(%s %s %s)" $1 $2 $3)))) Thoughts? Thanks, -- Aaron Ecay
>From c44b9b1f9a88e3bb88d1b4d9b59284ae840f02ce Mon Sep 17 00:00:00 2001 From: Aaron Ecay <aarone...@gmail.com> Date: Wed, 4 Nov 2015 12:13:07 +0000 Subject: [PATCH] macros: automatically quote the arguments to an eval macro * lisp/org-macro.el (org-macro-expand): Automatically quote the arguments to an eval macro. --- lisp/org-macro.el | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lisp/org-macro.el b/lisp/org-macro.el index 5f9c227..4858427 100644 --- a/lisp/org-macro.el +++ b/lisp/org-macro.el @@ -159,20 +159,24 @@ MACRO is an object, obtained, for example, with `org-element-context'. TEMPLATES is an alist of templates used for expansion. See `org-macro-templates' for a buffer-local default value. Return nil if no template was found." - (let ((template - ;; Macro names are case-insensitive. - (cdr (assoc-string (org-element-property :key macro) templates t)))) + (let* ((template + ;; Macro names are case-insensitive. + (cdr (assoc-string (org-element-property :key macro) templates t))) + ;; Macro starts with "(eval": it is a s-exp and will be `eval'-ed. + (evalp (string-match "\\`(eval\\>" template))) (when template (let ((value (replace-regexp-in-string "\\$[0-9]+" (lambda (arg) - (or (nth (1- (string-to-number (substring arg 1))) - (org-element-property :args macro)) - ;; No argument: remove place-holder. - "")) + (let ((arg-val (nth (1- (string-to-number (substring arg 1))) + (org-element-property :args macro)))) + (cond + (evalp (format "%S" arg-val)) + (arg-val arg-val) + ;; No argument: remove place-holder. + (t "")))) template nil 'literal))) - ;; VALUE starts with "(eval": it is a s-exp, `eval' it. - (when (string-match "\\`(eval\\>" value) + (when evalp (setq value (eval (read value)))) ;; Return string. (format "%s" (or value "")))))) -- 2.6.2