aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Whitton2022-04-11 09:20:35 -0700
committerSean Whitton2022-04-11 23:01:55 -0700
commit2e9111813b1dfdda1bf56c2b70a4220dbd8abce1 (patch)
treee55c50ac4a5d63538cc693e5e5dfa3b5f8f04d2a
parente2b64f8999f79a5820ba00d2987885d7dda492d5 (diff)
downloademacs-2e9111813b1dfdda1bf56c2b70a4220dbd8abce1.tar.gz
emacs-2e9111813b1dfdda1bf56c2b70a4220dbd8abce1.zip
Add two classic Common Lisp macro-writing macros
* lisp/emacs-lisp/cl-macs.el (cl-with-gensyms, cl-once-only): New macros.
-rw-r--r--lisp/emacs-lisp/cl-macs.el51
1 files changed, 51 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index da7157f4341..af8855516ca 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2430,6 +2430,57 @@ by EXPANSION, and (setq NAME ...) will act like (setf EXPANSION ...).
2430 (unless advised 2430 (unless advised
2431 (advice-remove 'macroexpand #'cl--sm-macroexpand))))) 2431 (advice-remove 'macroexpand #'cl--sm-macroexpand)))))
2432 2432
2433;;;###autoload
2434(defmacro cl-with-gensyms (names &rest body)
2435 "Bind each of NAMES to an uninterned symbol and evaluate BODY."
2436 (declare (debug (sexp body)) (indent 1))
2437 `(let ,(cl-loop for name in names collect
2438 `(,name (gensym (symbol-name ',name))))
2439 ,@body))
2440
2441;;;###autoload
2442(defmacro cl-once-only (names &rest body)
2443 "Generate code to evaluate each of NAMES just once in BODY.
2444
2445This macro helps with writing other macros. Each of names is
2446either (NAME FORM) or NAME, which latter means (NAME NAME).
2447During macroexpansion, each NAME is bound to an uninterned
2448symbol. The expansion evaluates each FORM and binds it to the
2449corresponding uninterned symbol.
2450
2451For example, consider this macro:
2452
2453 (defmacro my-cons (x)
2454 (cl-once-only (x)
2455 \\=`(cons ,x ,x)))
2456
2457The call (my-cons (pop y)) will expand to something like this:
2458
2459 (let ((g1 (pop y)))
2460 (cons g1 g1))
2461
2462The use of `cl-once-only' ensures that the pop is performed only
2463once, as intended.
2464
2465See also `macroexp-let2'."
2466 (declare (debug (sexp body)) (indent 1))
2467 (setq names (mapcar #'ensure-list names))
2468 (let ((our-gensyms (cl-loop for _ in names collect (gensym))))
2469 ;; During macroexpansion, obtain a gensym for each NAME.
2470 `(let ,(cl-loop for sym in our-gensyms collect `(,sym (gensym)))
2471 ;; Evaluate each FORM and bind to the corresponding gensym.
2472 ;;
2473 ;; We require this explicit call to `list' rather than using
2474 ;; (,,@(cl-loop ...)) due to a limitation of Elisp's backquote.
2475 `(let ,(list
2476 ,@(cl-loop for name in names and gensym in our-gensyms
2477 for to-eval = (or (cadr name) (car name))
2478 collect ``(,,gensym ,,to-eval)))
2479 ;; During macroexpansion, bind each NAME to its gensym.
2480 ,(let ,(cl-loop for name in names and gensym in our-gensyms
2481 collect `(,(car name) ,gensym))
2482 ,@body)))))
2483
2433;;; Multiple values. 2484;;; Multiple values.
2434 2485
2435;;;###autoload 2486;;;###autoload