Function: cl-labels
cl-labels is an autoloaded macro defined in cl-macs.el.gz.
Signature
(cl-labels ((FUNC ARGLIST BODY...) ...) FORM...)
Documentation
Make local (recursive) function definitions.
Each definition can take the form (FUNC EXP) where FUNC is the function
name, and EXP is an expression that returns the function value to which
it should be bound, or it can take the more common form (FUNC ARGLIST
BODY...) which is a shorthand for (FUNC (lambda ARGLIST BODY))
where BODY is wrapped in a cl-block named FUNC.
FUNC is in scope in any BODY or EXP, as well as in FORM, so you can write recursive and mutually recursive function definitions, with the caveat that EXPs are evaluated in sequence and you cannot call a FUNC before its EXP has been evaluated. See Info node (cl) Function Bindings for details.
Probably introduced at or before Emacs version 24.3.
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/cl-macs.el.gz
;;;###autoload
(defmacro cl-labels (bindings &rest body)
"Make local (recursive) function definitions.
Each definition can take the form (FUNC EXP) where FUNC is the function
name, and EXP is an expression that returns the function value to which
it should be bound, or it can take the more common form (FUNC ARGLIST
BODY...) which is a shorthand for (FUNC (lambda ARGLIST BODY))
where BODY is wrapped in a `cl-block' named FUNC.
FUNC is in scope in any BODY or EXP, as well as in FORM, so you can write
recursive and mutually recursive function definitions, with the caveat
that EXPs are evaluated in sequence and you cannot call a FUNC before its
EXP has been evaluated.
See Info node `(cl) Function Bindings' for details.
\(fn ((FUNC ARGLIST BODY...) ...) FORM...)"
(declare (indent 1) (debug cl-flet))
(let ((binds ()) (newenv macroexpand-all-environment))
(dolist (binding bindings)
(let ((var (make-symbol (format "--cl-%s--" (car binding)))))
(push (cons var binding) binds)
(push (cons (car binding)
(lambda (&rest args)
(if (eq (car args) cl--labels-magic)
(list cl--labels-magic var)
(cl-list* 'funcall var args))))
newenv)))
;; Don't override lexical-let's macro-expander.
(unless (assq 'function newenv)
(push (cons 'function #'cl--labels-convert) newenv))
;; Perform self-tail call elimination.
`(letrec ,(mapcar
(lambda (bind)
(pcase-let* ((`(,var ,fun ,sargs . ,sbody) bind))
`(,var ,(cl--self-tco-on-form
var (macroexpand-all
(if (null sbody)
sargs ;A (FUNC EXP) definition.
(let ((parsed-body
(macroexp-parse-body sbody)))
`(cl-function
(lambda ,sargs
,@(car parsed-body)
(cl-block ,fun
,@(cdr parsed-body))))))
newenv)))))
(nreverse binds))
. ,(macroexp-unprogn
(macroexpand-all
(macroexp-progn body)
newenv)))))