Function: org-lint-invalid-macro-argument-and-template

org-lint-invalid-macro-argument-and-template is a byte-compiled function defined in org-lint.el.gz.

Signature

(org-lint-invalid-macro-argument-and-template AST)

Source Code

;; Defined in /usr/src/emacs/lisp/org/org-lint.el.gz
(defun org-lint-invalid-macro-argument-and-template (ast)
  (let* ((reports nil)
         (extract-placeholders
	  (lambda (template)
	    (let ((start 0)
		  args)
	      (while (string-match "\\$\\([1-9][0-9]*\\)" template start)
                (setf start (match-end 0))
                (push (string-to-number (match-string 1 template)) args))
	      (sort (org-uniquify args) #'<))))
         (check-arity
          (lambda (arity macro)
            (let* ((name (org-element-property :key macro))
                   (pos (org-element-begin macro))
                   (args (org-element-property :args macro))
                   (l (length args)))
              (cond
               ((< l (1- (car arity)))
                (push (list pos (format "Missing arguments in macro %S" name))
                      reports))
               ((< l (car arity))
                (push (list pos (format "Missing argument in macro %S" name))
                      reports))
               ((> l (1+ (cdr arity)))
                (push (let ((spurious-args (nthcdr (cdr arity) args)))
                        (list pos
                              (format "Spurious arguments in macro %S: %s"
                                      name
                                      (mapconcat #'org-trim spurious-args ", "))))
                      reports))
               ((> l (cdr arity))
                (push (list pos
                            (format "Spurious argument in macro %S: %s"
                                    name
                                    (org-last args)))
                      reports))
               (t nil))))))
    ;; Check arguments for macro templates.
    (org-element-map ast 'keyword
      (lambda (k)
	(when (string= (org-element-property :key k) "MACRO")
	  (let* ((value (org-element-property :value k))
		 (name (and (string-match "^\\S-+" value)
			    (match-string 0 value)))
		 (template (and name
				(org-trim (substring value (match-end 0))))))
	    (cond
	     ((not name)
	      (push (list (org-element-post-affiliated k)
			  "Missing name in MACRO keyword")
		    reports))
	     ((not (org-string-nw-p template))
	      (push (list (org-element-post-affiliated k)
			  "Missing template in macro \"%s\"" name)
		    reports))
	     (t
	      (unless (let ((args (funcall extract-placeholders template)))
			(equal (number-sequence 1 (or (org-last args) 0)) args))
		(push (list (org-element-post-affiliated k)
			    (format "Unused placeholders in macro \"%s\""
				    name))
		      reports))))))))
    ;; Check arguments for macros.
    (org-macro-initialize-templates)
    (let ((templates (append
		      (mapcar (lambda (m) (cons m "$1"))
			      '("author" "date" "email" "title" "results"))
		      org-macro-templates)))
      (org-element-map ast 'macro
	(lambda (macro)
	  (let* ((name (org-element-property :key macro))
		 (template (cdr (assoc-string name templates t))))
            (pcase template
              (`nil
               (push (list (org-element-begin macro)
			   (format "Undefined macro %S" name))
		     reports))
              ((guard (string= name "keyword"))
               (funcall check-arity '(1 . 1) macro))
              ((guard (string= name "modification-time"))
               (funcall check-arity '(1 . 2) macro))
              ((guard (string= name "n"))
               (funcall check-arity '(0 . 2) macro))
              ((guard (string= name "property"))
               (funcall check-arity '(1 . 2) macro))
              ((guard (string= name "time"))
               (funcall check-arity '(1 . 1) macro))
              ((pred functionp))        ;ignore (eval ...) templates
              (_
               (let* ((arg-numbers (funcall extract-placeholders template))
                      (arity (if (null arg-numbers)
                                 '(0 . 0)
                               (let ((m (apply #'max arg-numbers)))
                                 (cons m m)))))
                 (funcall check-arity arity macro))))))))
    reports))