all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Sean Whitton <spwhitton@spwhitton.name>
To: emacs-devel@gnu.org
Subject: [PATCH] Adding with-gensyms and once-only to subr-x
Date: Mon, 11 Apr 2022 09:26:36 -0700	[thread overview]
Message-ID: <87a6crr3gj.fsf@athena.silentflame.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 276 bytes --]

Hello,

Lately I have been finding myself wanting with-gensyms and once-only,
two classic macro-writing macros, available in core Elisp.  (There is
already org-with-gensyms, but it's not in the least bit Org-specific.)

Here is my implementation for review.

-- 
Sean Whitton

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-lisp-emacs-lisp-subr-x.el-with-gensyms-once-only-New.patch --]
[-- Type: text/x-diff, Size: 2430 bytes --]

From 89e86db1ccb97ce3f91d5b4beb5d7b461311d196 Mon Sep 17 00:00:00 2001
From: Sean Whitton <spwhitton@spwhitton.name>
Date: Mon, 11 Apr 2022 09:20:35 -0700
Subject: [PATCH] * lisp/emacs-lisp/subr-x.el (with-gensyms, once-only): New
 macros.

---
 lisp/emacs-lisp/subr-x.el | 43 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index abf85ab6c6..c74bf7f5f0 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -526,6 +526,49 @@ read-process-name
         (error "No process selected"))
       process)))
 
+(defmacro with-gensyms (names &rest body)
+  "Bind each of NAMES to an uninterned symbol and evaluate BODY."
+  (declare (debug (sexp body)) (indent 1))
+  `(let ,(cl-loop for name in names collect
+                  `(,name (gensym (symbol-name ',name))))
+     ,@body))
+
+(defmacro once-only (names &rest body)
+  "Generate code to evaluate each of NAMES just once in BODY.
+
+This macro helps with writing other macros.  Each of names is
+either (NAME FORM) or NAME, which latter means (NAME NAME).
+During macroexpansion, each NAME is bound to an uninterned
+symbol.  The expansion evaluates each FORM and binds it to the
+corresponding uninterned symbol.
+
+For example, consider this macro:
+
+    (defmacro my-cons (x)
+      (once-only (x)
+        `(cons ,x ,x)))
+
+Consider the call (my-cons (pop y)).  This will expand to
+something like this:
+
+    (let ((g1 (pop y)))
+      (cons g1 g1))
+
+This ensures that the pop is performed only once, as wanted."
+  (declare (debug (sexp body)) (indent 1))
+  (setq names (mapcar #'ensure-list names))
+  (let ((our-gensyms (cl-loop for name in names collect (gensym))))
+    ;; During macroexpansion, obtain a gensym for each NAME.
+    `(let ,(cl-loop for sym in our-gensyms collect `(,sym (gensym)))
+       ;; Evaluate each FORM and bind to the corresponding gensym.
+       `(let (,,@(cl-loop for name in names and gensym in our-gensyms
+                          for to-eval = (or (cadr name) (car name))
+                          collect ``(,,gensym ,,to-eval)))
+          ;; During macroexpansion, bind each NAME to its gensym.
+          ,(let ,(cl-loop for name in names and gensym in our-gensyms
+                          collect `(,(car name) ,gensym))
+             ,@body)))))
+
 (provide 'subr-x)
 
 ;;; subr-x.el ends here
-- 
2.30.2


             reply	other threads:[~2022-04-11 16:26 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-11 16:26 Sean Whitton [this message]
2022-04-11 16:48 ` [PATCH] Adding with-gensyms and once-only to subr-x Stefan Monnier
2022-04-11 17:01   ` Sean Whitton
2022-04-11 17:26     ` Stefan Monnier
2022-04-11 18:41       ` Sean Whitton
2022-04-11 19:11         ` Stefan Monnier
2022-04-11 20:25           ` Sean Whitton
2022-04-11 21:11             ` Stefan Monnier
2022-04-11 23:05               ` Sean Whitton
2022-04-11 23:15                 ` Sean Whitton
2022-04-12  0:06           ` Sean Whitton
2022-04-12  3:08             ` Stefan Monnier
2022-04-12  6:02               ` Sean Whitton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87a6crr3gj.fsf@athena.silentflame.com \
    --to=spwhitton@spwhitton.name \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.