From c6c9dfc8670f5698634a8d5853853056ff928974 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Wed, 7 Sep 2022 13:48:20 +0200 Subject: [PATCH] Simplify dolist and dotimes We no longer care enough about non-lexbind code generation for it to merit special attention; better to keep the code simple. Suggested by Philip Kaludercic in https://lists.gnu.org/archive/html/emacs-devel/2022-09/msg00354.html . * lisp/subr.el (dolist, dotimes): Use uninterned symbols for variable bindings generated by the macros, and discard the alternative code versions for non-lexbind code. Use sensible variable names. --- lisp/subr.el | 68 +++++++++++++++------------------------------------- 1 file changed, 19 insertions(+), 49 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index e4d32455371..03d678f20d7 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -311,29 +311,13 @@ Then evaluate RESULT to get return value, default nil. (signal 'wrong-type-argument (list 'consp spec))) (unless (<= 2 (length spec) 3) (signal 'wrong-number-of-arguments (list '(2 . 3) (length spec)))) - ;; It would be cleaner to create an uninterned symbol, - ;; but that uses a lot more space when many functions in many files - ;; use dolist. - ;; FIXME: This cost disappears in byte-compiled lexical-binding files. - (let ((temp '--dolist-tail--)) - ;; This test does not matter much because both semantics are acceptable, - ;; but one is slightly faster with dynamic scoping and the other is - ;; slightly faster (and has cleaner semantics) with lexical scoping. - (if lexical-binding - `(let ((,temp ,(nth 1 spec))) - (while ,temp - (let ((,(car spec) (car ,temp))) - ,@body - (setq ,temp (cdr ,temp)))) - ,@(cdr (cdr spec))) - `(let ((,temp ,(nth 1 spec)) - ,(car spec)) - (while ,temp - (setq ,(car spec) (car ,temp)) + (let ((tail (make-symbol "tail"))) + `(let ((,tail ,(nth 1 spec))) + (while ,tail + (let ((,(car spec) (car ,tail))) ,@body - (setq ,temp (cdr ,temp))) - ,@(if (cdr (cdr spec)) - `((setq ,(car spec) nil) ,@(cdr (cdr spec)))))))) + (setq ,tail (cdr ,tail)))) + ,@(cdr (cdr spec))))) (defmacro dotimes (spec &rest body) "Loop a certain number of times. @@ -346,33 +330,19 @@ in compilation warnings about unused variables. \(fn (VAR COUNT [RESULT]) BODY...)" (declare (indent 1) (debug dolist)) - ;; It would be cleaner to create an uninterned symbol, - ;; but that uses a lot more space when many functions in many files - ;; use dotimes. - ;; FIXME: This cost disappears in byte-compiled lexical-binding files. - (let ((temp '--dotimes-limit--) - (start 0) - (end (nth 1 spec))) - ;; This test does not matter much because both semantics are acceptable, - ;; but one is slightly faster with dynamic scoping and the other has - ;; cleaner semantics. - (if lexical-binding - (let ((counter '--dotimes-counter--)) - `(let ((,temp ,end) - (,counter ,start)) - (while (< ,counter ,temp) - (let ((,(car spec) ,counter)) - ,@body) - (setq ,counter (1+ ,counter))) - ,@(if (cddr spec) - ;; FIXME: This let often leads to "unused var" warnings. - `((let ((,(car spec) ,counter)) ,@(cddr spec)))))) - `(let ((,temp ,end) - (,(car spec) ,start)) - (while (< ,(car spec) ,temp) - ,@body - (setq ,(car spec) (1+ ,(car spec)))) - ,@(cdr (cdr spec)))))) + (let ((var (nth 0 spec)) + (end (nth 1 spec)) + (upper-bound (make-symbol "upper-bound")) + (counter (make-symbol "counter"))) + `(let ((,upper-bound ,end) + (,counter 0)) + (while (< ,counter ,upper-bound) + (let ((,var ,counter)) + ,@body) + (setq ,counter (1+ ,counter))) + ,@(if (cddr spec) + ;; FIXME: This let often leads to "unused var" warnings. + `((let ((,var ,counter)) ,@(cddr spec))))))) (defmacro declare (&rest _specs) "Do not evaluate any arguments, and return nil. -- 2.39.2