Signal an error when a circular macro expansion happens

* lisp/org.el (org-macro-replace-all): Signal an error when a circular
  macro expansion happens.
(org-macro-initialize-templates): Fix docstring.
* testing/lisp/test-org.el: Add test.
This commit is contained in:
Nicolas Goaziou 2012-10-30 09:24:55 +01:00
parent 1f3a2c42c6
commit 6290da183c
2 changed files with 36 additions and 18 deletions

View File

@ -20927,28 +20927,40 @@ TEMPLATES is an alist of templates used for expansion. See
`org-macro-templates' for a buffer-local default value."
(save-excursion
(goto-char (point-min))
(while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
(let ((object (org-element-context)))
(when (eq (org-element-type object) 'macro)
(let ((value (org-macro-expand object templates)))
(when value
(delete-region
(org-element-property :begin object)
;; Preserve white spaces after the macro.
(progn (goto-char (org-element-property :end object))
(skip-chars-backward " \t")
(point)))
;; Leave point before replacement in case of recursive
;; expansions.
(save-excursion (insert value)))))))))
(let (record)
(while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
(let ((object (org-element-context)))
(when (eq (org-element-type object) 'macro)
(let* ((value (org-macro-expand object templates))
(begin (org-element-property :begin object))
(signature (list begin
object
(org-element-property :args object))))
;; Avoid circular dependencies by checking if the same
;; macro with the same arguments is expanded at the same
;; position twice.
(if (member signature record)
(error "Circular macro expansion: %s"
(org-element-property :key object))
(when value
(push signature record)
(delete-region
begin
;; Preserve white spaces after the macro.
(progn (goto-char (org-element-property :end object))
(skip-chars-backward " \t")
(point)))
;; Leave point before replacement in case of recursive
;; expansions.
(save-excursion (insert value)))))))))))
(defun org-macro-initialize-templates ()
"Collect macro templates defined in current buffer.
Templates are stored in buffer-local variable
`org-macro-templates'. In addition to buffer-defined macros, the
function installs the following ones: \"property\", \"date\",
\"time\". and, if appropriate, \"input-file\" and
\"modification-time\"."
function installs the following ones: \"property\",
\"time\". and, if the buffer is associated to a file,
\"input-file\" and \"modification-time\"."
(let ((case-fold-search t)
(set-template
(lambda (cell)

View File

@ -410,7 +410,13 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
"#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\n{{{out}}}"
(progn (org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates)
(buffer-string))))))
(buffer-string)))))
;; Error out when macro expansion is circular.
(should-error
(org-test-with-temp-text
"#+MACRO: mac1 {{{mac2}}}\n#+MACRO: mac2 {{{mac1}}}\n{{{mac1}}}"
(org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates))))