mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-03 10:31:37 -08:00
Move the when-let family of macros to subr.el
* lisp/subr.el (internal--build-binding) (internal--build-bindings): Moved from subr-x.el and rewritten to not use the threading macro. (if-let*, when-let*, and-let*, if-let, when-let): Moved from subr-x.el. This avoids breaking the build every time somebody uses these macros in functions that end up being called during bootstrap.
This commit is contained in:
parent
93549c2b28
commit
b05a103ea7
2 changed files with 96 additions and 110 deletions
|
|
@ -81,116 +81,6 @@ Note how the single `-' got converted into a list before
|
||||||
threading."
|
threading."
|
||||||
(declare (indent 0) (debug thread-first))
|
(declare (indent 0) (debug thread-first))
|
||||||
`(internal--thread-argument nil ,@forms))
|
`(internal--thread-argument nil ,@forms))
|
||||||
|
|
||||||
(defsubst internal--listify (elt)
|
|
||||||
"Wrap ELT in a list if it is not one.
|
|
||||||
If ELT is of the form ((EXPR)), listify (EXPR) with a dummy symbol."
|
|
||||||
(cond
|
|
||||||
((symbolp elt) (list elt elt))
|
|
||||||
((null (cdr elt))
|
|
||||||
(list (make-symbol "s") (car elt)))
|
|
||||||
(t elt)))
|
|
||||||
|
|
||||||
(defsubst internal--check-binding (binding)
|
|
||||||
"Check BINDING is properly formed."
|
|
||||||
(when (> (length binding) 2)
|
|
||||||
(signal
|
|
||||||
'error
|
|
||||||
(cons "`let' bindings can have only one value-form" binding)))
|
|
||||||
binding)
|
|
||||||
|
|
||||||
(defsubst internal--build-binding-value-form (binding prev-var)
|
|
||||||
"Build the conditional value form for BINDING using PREV-VAR."
|
|
||||||
(let ((var (car binding)))
|
|
||||||
`(,var (and ,prev-var ,(cadr binding)))))
|
|
||||||
|
|
||||||
(defun internal--build-binding (binding prev-var)
|
|
||||||
"Check and build a single BINDING with PREV-VAR."
|
|
||||||
(thread-first
|
|
||||||
binding
|
|
||||||
internal--listify
|
|
||||||
internal--check-binding
|
|
||||||
(internal--build-binding-value-form prev-var)))
|
|
||||||
|
|
||||||
(defun internal--build-bindings (bindings)
|
|
||||||
"Check and build conditional value forms for BINDINGS."
|
|
||||||
(let ((prev-var t))
|
|
||||||
(mapcar (lambda (binding)
|
|
||||||
(let ((binding (internal--build-binding binding prev-var)))
|
|
||||||
(setq prev-var (car binding))
|
|
||||||
binding))
|
|
||||||
bindings)))
|
|
||||||
|
|
||||||
(defmacro if-let* (varlist then &rest else)
|
|
||||||
"Bind variables according to VARLIST and evaluate THEN or ELSE.
|
|
||||||
This is like `if-let' but doesn't handle a VARLIST of the form
|
|
||||||
\(SYMBOL SOMETHING) specially."
|
|
||||||
(declare (indent 2)
|
|
||||||
(debug ((&rest [&or symbolp (symbolp form) (form)])
|
|
||||||
body)))
|
|
||||||
(if varlist
|
|
||||||
`(let* ,(setq varlist (internal--build-bindings varlist))
|
|
||||||
(if ,(caar (last varlist))
|
|
||||||
,then
|
|
||||||
,@else))
|
|
||||||
`(let* () ,then)))
|
|
||||||
|
|
||||||
(defmacro when-let* (varlist &rest body)
|
|
||||||
"Bind variables according to VARLIST and conditionally evaluate BODY.
|
|
||||||
This is like `when-let' but doesn't handle a VARLIST of the form
|
|
||||||
\(SYMBOL SOMETHING) specially."
|
|
||||||
(declare (indent 1) (debug if-let*))
|
|
||||||
(list 'if-let* varlist (macroexp-progn body)))
|
|
||||||
|
|
||||||
(defmacro and-let* (varlist &rest body)
|
|
||||||
"Bind variables according to VARLIST and conditionally evaluate BODY.
|
|
||||||
Like `when-let*', except if BODY is empty and all the bindings
|
|
||||||
are non-nil, then the result is non-nil."
|
|
||||||
(declare (indent 1) (debug if-let*))
|
|
||||||
(let (res)
|
|
||||||
(if varlist
|
|
||||||
`(let* ,(setq varlist (internal--build-bindings varlist))
|
|
||||||
(when ,(setq res (caar (last varlist)))
|
|
||||||
,@(or body `(,res))))
|
|
||||||
`(let* () ,@(or body '(t))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defmacro if-let (spec then &rest else)
|
|
||||||
"Bind variables according to SPEC and evaluate THEN or ELSE.
|
|
||||||
Evaluate each binding in turn, as in `let*', stopping if a
|
|
||||||
binding value is nil. If all are non-nil return the value of
|
|
||||||
THEN, otherwise the last form in ELSE.
|
|
||||||
|
|
||||||
Each element of SPEC is a list (SYMBOL VALUEFORM) that binds
|
|
||||||
SYMBOL to the value of VALUEFORM. An element can additionally be
|
|
||||||
of the form (VALUEFORM), which is evaluated and checked for nil;
|
|
||||||
i.e. SYMBOL can be omitted if only the test result is of
|
|
||||||
interest. It can also be of the form SYMBOL, then the binding of
|
|
||||||
SYMBOL is checked for nil.
|
|
||||||
|
|
||||||
As a special case, interprets a SPEC of the form \(SYMBOL SOMETHING)
|
|
||||||
like \((SYMBOL SOMETHING)). This exists for backward compatibility
|
|
||||||
with an old syntax that accepted only one binding."
|
|
||||||
(declare (indent 2)
|
|
||||||
(debug ([&or (symbolp form) ; must be first, Bug#48489
|
|
||||||
(&rest [&or symbolp (symbolp form) (form)])]
|
|
||||||
body)))
|
|
||||||
(when (and (<= (length spec) 2)
|
|
||||||
(not (listp (car spec))))
|
|
||||||
;; Adjust the single binding case
|
|
||||||
(setq spec (list spec)))
|
|
||||||
(list 'if-let* spec then (macroexp-progn else)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defmacro when-let (spec &rest body)
|
|
||||||
"Bind variables according to SPEC and conditionally evaluate BODY.
|
|
||||||
Evaluate each binding in turn, stopping if a binding value is nil.
|
|
||||||
If all are non-nil, return the value of the last form in BODY.
|
|
||||||
|
|
||||||
The variable list SPEC is the same as in `if-let'."
|
|
||||||
(declare (indent 1) (debug if-let))
|
|
||||||
(list 'if-let spec (macroexp-progn body)))
|
|
||||||
|
|
||||||
(defsubst hash-table-empty-p (hash-table)
|
(defsubst hash-table-empty-p (hash-table)
|
||||||
"Check whether HASH-TABLE is empty (has 0 elements)."
|
"Check whether HASH-TABLE is empty (has 0 elements)."
|
||||||
(zerop (hash-table-count hash-table)))
|
(zerop (hash-table-count hash-table)))
|
||||||
|
|
|
||||||
96
lisp/subr.el
96
lisp/subr.el
|
|
@ -2371,6 +2371,102 @@ Affects only hooks run in the current buffer."
|
||||||
(let ((delay-mode-hooks t))
|
(let ((delay-mode-hooks t))
|
||||||
,@body)))
|
,@body)))
|
||||||
|
|
||||||
|
;;; `when-let' and friends.
|
||||||
|
|
||||||
|
(defun internal--build-binding (binding prev-var)
|
||||||
|
"Check and build a single BINDING with PREV-VAR."
|
||||||
|
(setq binding
|
||||||
|
(cond
|
||||||
|
((symbolp binding)
|
||||||
|
(list binding binding))
|
||||||
|
((null (cdr binding))
|
||||||
|
(list (make-symbol "s") (car binding)))
|
||||||
|
(t binding)))
|
||||||
|
(when (> (length binding) 2)
|
||||||
|
(signal 'error
|
||||||
|
(cons "`let' bindings can have only one value-form" binding)))
|
||||||
|
(let ((var (car binding)))
|
||||||
|
`(,var (and ,prev-var ,(cadr binding)))))
|
||||||
|
|
||||||
|
(defun internal--build-bindings (bindings)
|
||||||
|
"Check and build conditional value forms for BINDINGS."
|
||||||
|
(let ((prev-var t))
|
||||||
|
(mapcar (lambda (binding)
|
||||||
|
(let ((binding (internal--build-binding binding prev-var)))
|
||||||
|
(setq prev-var (car binding))
|
||||||
|
binding))
|
||||||
|
bindings)))
|
||||||
|
|
||||||
|
(defmacro if-let* (varlist then &rest else)
|
||||||
|
"Bind variables according to VARLIST and evaluate THEN or ELSE.
|
||||||
|
This is like `if-let' but doesn't handle a VARLIST of the form
|
||||||
|
\(SYMBOL SOMETHING) specially."
|
||||||
|
(declare (indent 2)
|
||||||
|
(debug ((&rest [&or symbolp (symbolp form) (form)])
|
||||||
|
body)))
|
||||||
|
(if varlist
|
||||||
|
`(let* ,(setq varlist (internal--build-bindings varlist))
|
||||||
|
(if ,(caar (last varlist))
|
||||||
|
,then
|
||||||
|
,@else))
|
||||||
|
`(let* () ,then)))
|
||||||
|
|
||||||
|
(defmacro when-let* (varlist &rest body)
|
||||||
|
"Bind variables according to VARLIST and conditionally evaluate BODY.
|
||||||
|
This is like `when-let' but doesn't handle a VARLIST of the form
|
||||||
|
\(SYMBOL SOMETHING) specially."
|
||||||
|
(declare (indent 1) (debug if-let*))
|
||||||
|
(list 'if-let* varlist (macroexp-progn body)))
|
||||||
|
|
||||||
|
(defmacro and-let* (varlist &rest body)
|
||||||
|
"Bind variables according to VARLIST and conditionally evaluate BODY.
|
||||||
|
Like `when-let*', except if BODY is empty and all the bindings
|
||||||
|
are non-nil, then the result is non-nil."
|
||||||
|
(declare (indent 1) (debug if-let*))
|
||||||
|
(let (res)
|
||||||
|
(if varlist
|
||||||
|
`(let* ,(setq varlist (internal--build-bindings varlist))
|
||||||
|
(when ,(setq res (caar (last varlist)))
|
||||||
|
,@(or body `(,res))))
|
||||||
|
`(let* () ,@(or body '(t))))))
|
||||||
|
|
||||||
|
(defmacro if-let (spec then &rest else)
|
||||||
|
"Bind variables according to SPEC and evaluate THEN or ELSE.
|
||||||
|
Evaluate each binding in turn, as in `let*', stopping if a
|
||||||
|
binding value is nil. If all are non-nil return the value of
|
||||||
|
THEN, otherwise the last form in ELSE.
|
||||||
|
|
||||||
|
Each element of SPEC is a list (SYMBOL VALUEFORM) that binds
|
||||||
|
SYMBOL to the value of VALUEFORM. An element can additionally be
|
||||||
|
of the form (VALUEFORM), which is evaluated and checked for nil;
|
||||||
|
i.e. SYMBOL can be omitted if only the test result is of
|
||||||
|
interest. It can also be of the form SYMBOL, then the binding of
|
||||||
|
SYMBOL is checked for nil.
|
||||||
|
|
||||||
|
As a special case, interprets a SPEC of the form \(SYMBOL SOMETHING)
|
||||||
|
like \((SYMBOL SOMETHING)). This exists for backward compatibility
|
||||||
|
with an old syntax that accepted only one binding."
|
||||||
|
(declare (indent 2)
|
||||||
|
(debug ([&or (symbolp form) ; must be first, Bug#48489
|
||||||
|
(&rest [&or symbolp (symbolp form) (form)])]
|
||||||
|
body)))
|
||||||
|
(when (and (<= (length spec) 2)
|
||||||
|
(not (listp (car spec))))
|
||||||
|
;; Adjust the single binding case
|
||||||
|
(setq spec (list spec)))
|
||||||
|
(list 'if-let* spec then (macroexp-progn else)))
|
||||||
|
|
||||||
|
(defmacro when-let (spec &rest body)
|
||||||
|
"Bind variables according to SPEC and conditionally evaluate BODY.
|
||||||
|
Evaluate each binding in turn, stopping if a binding value is nil.
|
||||||
|
If all are non-nil, return the value of the last form in BODY.
|
||||||
|
|
||||||
|
The variable list SPEC is the same as in `if-let'."
|
||||||
|
(declare (indent 1) (debug if-let))
|
||||||
|
(list 'if-let spec (macroexp-progn body)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; PUBLIC: find if the current mode derives from another.
|
;; PUBLIC: find if the current mode derives from another.
|
||||||
|
|
||||||
(defun provided-mode-derived-p (mode &rest modes)
|
(defun provided-mode-derived-p (mode &rest modes)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue