Function: loaddefs-generate--make-autoload

loaddefs-generate--make-autoload is a byte-compiled function defined in loaddefs-gen.el.gz.

Signature

(loaddefs-generate--make-autoload FORM FILE &optional EXPANSION)

Documentation

Turn FORM into an autoload or defvar for source file FILE.

Returns nil if FORM is not a special autoload form (i.e. a function definition or macro definition or a defcustom). If EXPANSION is non-nil, we're processing the macro expansion of an expression, in which case we want to handle forms differently.

Note that macros can request expansion by including (autoload-macro expand) among their declare forms.

Aliases

make-autoload

Source Code

;; Defined in /usr/src/emacs/lisp/emacs-lisp/loaddefs-gen.el.gz
(defun loaddefs-generate--make-autoload (form file &optional expansion)
  "Turn FORM into an autoload or defvar for source file FILE.
Returns nil if FORM is not a special autoload form (i.e. a function definition
or macro definition or a defcustom).
If EXPANSION is non-nil, we're processing the macro expansion of an
expression, in which case we want to handle forms differently.

Note that macros can request expansion by including `(autoload-macro
expand)' among their `declare' forms."
  (let ((car (car-safe form)) expand)
    (cond
     ((and expansion (eq car 'defalias))
      (pcase-let*
          ((`(,_ ,_ ,arg . ,rest) form)
           ;; `type' is non-nil if it defines a macro.
           ;; `fun' is the function part of `arg' (defaults to `arg').
           ((or (and (or `(cons 'macro ,fun) `'(macro . ,fun)) (let type t))
                (and (let fun arg) (let type nil)))
            arg)
           ;; `lam' is the lambda expression in `fun' (or nil if not
           ;; recognized).
           (lam (if (memq (car-safe fun) '(quote function)) (cadr fun)))
           ;; `args' is the list of arguments (or t if not recognized).
           ;; `body' is the body of `lam' (or t if not recognized).
           ((or `(lambda ,args . ,body)
                (and (let args t) (let body t)))
            lam)
           ;; Get the `doc' from `body' or `rest'.
           (doc (cond ((stringp (car-safe body)) (car body))
                      ((stringp (car-safe rest)) (car rest))))
           ;; Look for an interactive spec.
           (interactive (pcase body
                          ((or `((interactive . ,iargs) . ,_)
                               `(,_ (interactive . ,iargs) . ,_))
                           ;; List of modes or just t.
                           (if (nthcdr 1 iargs)
                               (list 'quote (nthcdr 1 iargs))
                             t)))))
        ;; Add the usage form at the end where describe-function-1
        ;; can recover it.
        (when (consp args) (setq doc (help-add-fundoc-usage doc args)))
        (loaddefs-generate--shorten-autoload
         `(autoload ,(nth 1 form) ,file ,doc ,interactive ,type))))

     ;; Look inside `progn', and `eval-and-compile', since these
     ;; are often used in the expansion of things like `pcase-defmacro'.
     ((and expansion (memq car '(progn prog1 eval-and-compile)))
      (let ((end (memq :autoload-end form)))
	(when end             ;Cut-off anything after the :autoload-end marker.
          (setq form (copy-sequence form))
          (setcdr (memq :autoload-end form) nil))
        (let ((exps (delq nil (mapcar (lambda (form)
                                        (unless (eq form :autoload-end)
                                          (loaddefs-generate--make-autoload
                                           form file expansion)))
                                      (cdr form)))))
          (when exps (cons 'progn exps)))))

     ;; For macros which request it, try again on their expansion.
     ((progn
        ;; If the car is an unknown symbol, we load the file first to
        ;; give packages a chance to define their macros.
        (unless (or (not (symbolp car)) (fboundp car)
                    ;; Special cases handled below
                    (memq car loaddefs--defining-macros)
                    (memq car '(defclass defcustom deftheme defgroup nil))
                    (assoc file load-history)
                    (member file loaddefs--load-error-files))
          (let ((load-path (cons (file-name-directory file) load-path)))
            (message "loaddefs-gen: loading file %s (for %s)" file car)
            (condition-case e (load file)
              (error
               (push file loaddefs--load-error-files) ; do not attempt again
               (warn "loaddefs-gen: load error\n\t%s" e)))))
        (and (macrop car)
	     (eq 'expand (function-get car 'autoload-macro))
	     (setq expand (let ((load-true-file-name file)
				(load-file-name file))
			    (macroexpand-1 form)))
	     (not (eq car (car expand)))))
      ;; Recurse on the expansion.
      (loaddefs-generate--make-autoload expand file 'expansion))

     ;; For known special macros which define functions, use `autoload'
     ;; directly.
     ((memq car loaddefs--defining-macros)
      (let* ((name (nth 1 form))
	     (args (pcase car
                     ((or 'transient-define-prefix 'transient-define-suffix
                          'transient-define-infix 'transient-define-argument
                          'transient-define-group)
                      (nth 2 form))
                     (_ t)))
	     (body (nthcdr (or (function-get car 'doc-string-elt) 3) form))
	     (doc (if (stringp (car body)) (pop body))))
        ;; Add the usage form at the end where describe-function-1
        ;; can recover it.
	(when (listp args) (setq doc (help-add-fundoc-usage doc args)))
        ;; `define-generic-mode' quotes the name, so take care of that
        (loaddefs-generate--shorten-autoload
         `(autoload ,(if (listp name) name (list 'quote name))
            ,file ,doc
            ,(or (and (memq car '( transient-define-prefix
                                   transient-define-suffix
                                   transient-define-infix
                                   transient-define-argument
                                   transient-define-group))
                      t)
                 (and (eq (car-safe (car body)) 'interactive)
                      ;; List of modes or just t.
                      (or (if (nthcdr 2 (car body))
                              (list 'quote (nthcdr 2 (car body)))
                            t))))))))

     ;; For defclass forms, use `eieio-defclass-autoload'.
     ((eq car 'defclass)
      (let ((name (nth 1 form))
	    (superclasses (nth 2 form))
	    (doc (nth 4 form)))
	(list 'eieio-defclass-autoload (list 'quote name)
	      (list 'quote superclasses) file doc)))

     ;; Convert defcustom to less space-consuming data.
     ((eq car 'defcustom)
      (let* ((varname (car-safe (cdr-safe form)))
	     (props (nthcdr 4 form))
	     (initializer (plist-get props :initialize))
	     (init (car-safe (cdr-safe (cdr-safe form))))
	     (doc (car-safe (cdr-safe (cdr-safe (cdr-safe form)))))
	     ;; (rest (cdr-safe (cdr-safe (cdr-safe (cdr-safe form)))))
	     )
	`(progn
	   ,(if (not (member initializer '(nil 'custom-initialize-default
                                           #'custom-initialize-default
                                           'custom-initialize-reset
                                           #'custom-initialize-reset)))
                form
	      `(defvar ,varname ,init ,doc))
	   ;; When we include the complete `form', this `custom-autoload'
           ;; is not indispensable, but it still helps in case the `defcustom'
           ;; doesn't specify its group explicitly, and probably in a few other
           ;; corner cases.
	   (custom-autoload ',varname ,file
                            ,(condition-case nil
                                 (null (plist-get props :set))
                               (error nil)))
           ;; Propagate the :safe property to the loaddefs file.
           ,@(when-let* ((safe (plist-get props :safe)))
               `((put ',varname 'safe-local-variable ,safe))))))

     ;; Extract theme properties.
     ((eq car 'deftheme)
      (let* ((name (car-safe (cdr-safe form)))
	     (props (nthcdr 3 form)))
	`(put ',name 'theme-properties (list ,@props))))

     ((eq car 'defgroup)
      ;; In Emacs this is normally handled separately by cus-dep.el, but for
      ;; third party packages, it can be convenient to explicitly autoload
      ;; a group.
      (let ((groupname (nth 1 form))
            (parent (eval (plist-get form :group) t)))
        `(let ((loads (get ',groupname 'custom-loads)))
           (if (member ',file loads) nil
             (put ',groupname 'custom-loads (cons ',file loads))
             ,@(when parent
               `((put ',parent 'custom-loads
                      (cons ',groupname (get ',parent 'custom-loads)))))))))

     ;; When processing a macro expansion, any expression
     ;; before a :autoload-end should be included.  These are typically (put
     ;; 'fun 'prop val) and things like that.
     ((and expansion (consp form)) form)

     ;; nil here indicates that this is not a special autoload form.
     (t nil))))