From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: akater Newsgroups: gmane.emacs.devel Subject: cl-macs: default indentation for all arglists with top-level &body Date: Sun, 11 Apr 2021 12:35:34 +0000 Message-ID: <87blalt2w9.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="35014"; mail-complaints-to="usenet@ciao.gmane.io" To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Apr 11 14:57:37 2021 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lVZej-0008yz-S4 for ged-emacs-devel@m.gmane-mx.org; Sun, 11 Apr 2021 14:57:37 +0200 Original-Received: from localhost ([::1]:34686 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lVZei-0007GR-Ss for ged-emacs-devel@m.gmane-mx.org; Sun, 11 Apr 2021 08:57:36 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:52990) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lVZU7-0000ku-0x for emacs-devel@gnu.org; Sun, 11 Apr 2021 08:46:39 -0400 Original-Received: from mail-qv1-xf2d.google.com ([2607:f8b0:4864:20::f2d]:44800) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lVZU5-0005LD-4B for emacs-devel@gnu.org; Sun, 11 Apr 2021 08:46:38 -0400 Original-Received: by mail-qv1-xf2d.google.com with SMTP id o11so4961326qvh.11 for ; Sun, 11 Apr 2021 05:46:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version; bh=mKKJAmEq+AWtrMBiiA6GJChlS6916EY0PZEVHq7sspU=; b=Rzy6/WFuH88jzWPRXvZxnxLXIKLv6g8IaJw2GXmxjmflhUhDkgo+1xZJ9ur0EF+aia VuvbpDzdkCPz/VxJTUl2u1IyBCKw+HaJkZa697JcxpSaVfDHvzsfk/kx9qH31pKLzFPC Sda6ckhOaqGa5YdQTbxNqp1TTo3aEx4WIKHW0Qrr/EuJ1BN9FDKoB17/PjUNVGVo/DLG Yfz6Uz1pE682lDJ0QKBvjn6MNL03Ke/9pU1XefdA1QVd/rqKEihcTHXgfYHSCP5XXeLk i5dh6doD4bvBFE5OauL4+vcCTvu9xOpaz+KdGQXMOlmvP9IFQq3CpFxuviBw8b2uQtK3 zoag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version; bh=mKKJAmEq+AWtrMBiiA6GJChlS6916EY0PZEVHq7sspU=; b=s898Xbr4hb+tRXAG7xXwymjCgXkA4oujE3ZE0XW7SXgOXjaMHQTZfNGB+48Dt7zOAO lYF3Pl3ZDmOUAUepxQBQz0trL0CUlVXTSp3LAPKySLaK3Baoxu8zdf62fR2fXxzbAhyD usFhYS0V0IH0zXqHsBwxCh343A0892YQKgt/XCQCB534U1YwAgedye7DFocNvUkb9IO1 WLHOMOAK0sD4GwSIxX8GqJ+dpYeoI/jc1zcyH/Ok03aAs7lLQtBdWqGheXbwwVFm9xwo dThZdW11So6z/3XQL236YfUyHTEjZgRxY+toRtPhBAvRsZoOalhcxi0uFDsKYJHEValG LUgg== X-Gm-Message-State: AOAM5330FGxsJnNKmdLdSH6W+bsNugFThVOucoHHx/P92vcdUvZxmh1M jyFMYwD+5YTc7jslFNBEzTj98gOvmMH50w== X-Google-Smtp-Source: ABdhPJwwrfj7F0vTp3GkgKiTHWN3KYcko79axg1YfBR5B+631mrdGYT6lCMPIKhI6h05IRvVb2av8Q== X-Received: by 2002:a0c:8e84:: with SMTP id x4mr23041898qvb.54.1618145194605; Sun, 11 Apr 2021 05:46:34 -0700 (PDT) Original-Received: from localhost ([209.127.17.234]) by smtp.googlemail.com with ESMTPSA id l17sm5671498qtk.60.2021.04.11.05.46.33 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Apr 2021 05:46:34 -0700 (PDT) Received-SPF: pass client-ip=2607:f8b0:4864:20::f2d; envelope-from=nuclearspace@gmail.com; helo=mail-qv1-xf2d.google.com X-Spam_score_int: -7 X-Spam_score: -0.8 X-Spam_bar: / X-Spam_report: (-0.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_BL_SPAMCOP_NET=1.347, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:267869 Archived-At: --=-=-= Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" --==-=-= Content-Type: text/plain --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQJLBAEBCgA1FiEEgu5SJRdnQOF34djNsr6xYbHsf0QFAmBy7R4XHG51Y2xlYXJz cGFjZUBnbWFpbC5jb20ACgkQsr6xYbHsf0TdIxAAlYEivPPHWAz6J9sIKv1ap7oW b6C7A6YNTjzDIS9GNVs0ZJKzbdVSzurcmVNp7ecAvgclXJR1gFO57U2rjovtytdx TtYfmdgsxtA00lscy5nsU+h3qgY8lb9alUu/jiXMMCxCnRysQgDVT5KOxhHv6SZV 3ZKcwXYuuL0kNhk5Fzmmz2wrTSgztYVEc90kS5ZG37zyFrLxiBMJZQIl9bf+d3CD LuIytecKfZUD2BIdMNqjkE8o5KwcQsI3MUJtm9hB1RgykGdS02LHAAPyDkP7R0Hc aUKPEntad7QTuZVgVeAWEYX3NoA2TdVNY+NL2ly7+YomhseXv2ynjW8BkjZzBMRi 2tKpVadXDqr+zrDgIiw9p+Szb3VLdsblUvzJ6ecb76sU2Yj5xpCN4EzxDag8ZBdL Q/VbgYLomXFDXgPDa3ZgeV+Cpz1Z97I3p3KUQKKVUX/qeuTG4se1VGpE0nN5uO4O X/bOxzjUPJMH3ADPo9EFAExXq1IwlJM/axPoBrSr23pUDSiV5veO+1D52r8umLt+ gHYFZlT0kOgrSUOcZURCNbnHEwDw8GzlhKXTdgRPmvgIypIEaF3RlYgNXWvRaRXV 9E8N4PIGcuC0Wq52qEA9ZaLhuAhjMan3kfgymd/er1SM8ft/caXwigEEI3DwkJ91 Z8m+mU2y137orF/Z/ww= =sp+T -----END PGP SIGNATURE----- --==-=-=-- --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-cl-macs-default-indentation-for-all-arglists-with-to.patch Content-Description: cl-macs: indent via top-level &body >From 59e296eaf48494c60f5dcea88b9afd3db42b5764 Mon Sep 17 00:00:00 2001 From: akater Date: Sun, 11 Apr 2021 10:53:25 +0000 Subject: [PATCH] cl-macs: default indentation for all arglists with top-level &body --- lisp/emacs-lisp/cl-macs.el | 45 ++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 68211ec410..f04b9e9b5f 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -43,6 +43,8 @@ ;;; Code: +(eval-when-compile (require 'subr-x)) + (require 'cl-lib) (require 'macroexp) ;; `gv' is required here because cl-macs can be loaded before loaddefs.el. @@ -243,6 +245,20 @@ defvar cl--bind-defs) ;(DEF . DEFS) giving the "default default" for optargs. (defvar cl--bind-enquote) ;Non-nil if &cl-quote was in the formal arglist! (defvar cl--bind-lets) (defvar cl--bind-forms) +;;;###autoload +(defmacro cl-dolist (spec &rest body) + "Loop over a list. +Evaluate BODY with VAR bound to each `car' from LIST, in turn. +Then evaluate RESULT to get return value, default nil. +An implicit nil block is established around the loop. + +\(fn (VAR LIST [RESULT]) BODY...)" + (declare (debug ((symbolp form &optional form) cl-declarations body)) + (indent 1)) + (let ((loop `(dolist ,spec ,@body))) + (if (advice-member-p 'cl--wrap-in-nil-block 'dolist) + loop `(cl-block nil ,loop)))) + (defun cl--transform-lambda (form bind-block) "Transform a function form FORM of name BIND-BLOCK. BIND-BLOCK is the name of the symbol to which the function will be bound, @@ -319,6 +335,21 @@ defun cl--transform-lambda (form bind-block) (format "%S" (cons 'fn (cl--make-usage-args orig-args)))))) header))) + (when-let ((according-to-&body + (let ((counter 0)) + (cl-dolist (x orig-args) + (cond + ((eq '&body x) (cl-return counter)) + ((not (memq x cl--lambda-list-keywords)) + (cl-incf counter))))))) + ;; Placing the declaration in the end + ;; allows overriding the indentation setting + ;; with an explicit (declare (indent ..)) statement + ;; manually written in the form being expanded. + (setq header + (nconc header + (list + `(declare (indent ,according-to-&body)))))) ;; FIXME: we'd want to choose an arg name for the &rest param ;; and pass that as `expr' to cl--do-arglist, but that ends up ;; generating code with a redundant let-binding, so we instead @@ -1821,20 +1852,6 @@ defun cl--expand-do-loop (steps endtest body star) (apply #'append sets)))))) ,@(or (cdr endtest) '(nil))))) -;;;###autoload -(defmacro cl-dolist (spec &rest body) - "Loop over a list. -Evaluate BODY with VAR bound to each `car' from LIST, in turn. -Then evaluate RESULT to get return value, default nil. -An implicit nil block is established around the loop. - -\(fn (VAR LIST [RESULT]) BODY...)" - (declare (debug ((symbolp form &optional form) cl-declarations body)) - (indent 1)) - (let ((loop `(dolist ,spec ,@body))) - (if (advice-member-p 'cl--wrap-in-nil-block 'dolist) - loop `(cl-block nil ,loop)))) - ;;;###autoload (defmacro cl-dotimes (spec &rest body) "Loop a certain number of times. -- 2.26.2 --=-=-= Content-Type: text/plain (This has been discussed earlier on the list --- more on this later.) In Common Lisp, ~&body~ keyword is the same as ~&rest~ modulo indentation: #+begin_quote &body is identical in function to &rest, but it can be used to inform certain output-formatting and editing functions that the remainder of the form is treated as a body, and should be indented accordingly. #+end_quote --- [[http://clhs.lisp.se/Body/03_dd.htm][CLHS, 3.4.4 Macro Lambda Lists]] cl-macs does support ~&body~; however toplevel ~&body~ does not affect indentation. This can be fixed by augmenting the definition of ~cl--transform-lambda~ as follows: #+begin_example emacs-lisp (when-let ((according-to-&body (let ((counter 0)) (cl-dolist (x orig-args) (cond ((eq '&body x) (cl-return counter)) ((not (memq x cl--lambda-list-keywords)) (cl-incf counter))))))) ;; Placing the declaration in the end ;; allows overriding the indentation setting ;; with an explicit (declare (indent ..)) statement ;; manually written in the form being expanded. (setq header (nconc header (list `(declare (indent ,according-to-&body)))))) #+end_example See the attached patch for details. I hesitate to recommend using the patch as is because my use of ~cl-dolist~ likely interrupts the flow of cl-macs. In fact, the patch as is might actually break the build: unfortunately, I cannot do a test build of Emacs right now. I thus did not try to polish something I wouldn't actually be able to test. The patch is provided for the sake of completeness. Now to (possibly incomplete) summary of the 2005-07 thread and comparison. The feature was - suggested to be applied to usual ~defmacro~ as well - not implemented as there is no ~&body~ in ~defmacro~ - apparently shelved and then forgotten about I only suggest to alter ~cl-defmacro~. In addition, 2005-07 solution - is implemented with ~(put .. 'lisp-indent-function ..)~ - does not check for preceding keywords The link: https://lists.gnu.org/archive/html/emacs-devel/2005-07/msg00457.html I check for all ~cl--lambda-list-keywords~. This is excessive but it also makes for a cleaner code, properly treats arglists with ~&optional~, ~&whole~ (if ever implmeneted) and whatever else happens to be in the arglist; note that according to Common Lisp specification, arglsits can actually have arbitrary keywords. ~&whole~ is only relevant for macro definitions; arguably, it does make sense for ~cl--transform-lambda~ to take these types into account but I believe the presented approach is good enough, and using &-keywords as regular arguments in, say, ~cl-defun~ is certainly not a good idea. As to whether the macro better inject ~(put ..)~ or ~(declare ..)~ form, my preference is for the latter because - I find it preferable to modify headers rather than the body - I strongly prefer to generate code I myself would have written. This is apparently not a conventional practice in Lisp; mistakenly, I believe, but that's offtopic. Just in case, I have signed the papers already. --=-=-=--