From f488fb6528738131ef41859e1f04125f2e50efce Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Wed, 30 Mar 2011 14:40:00 -0400 Subject: [PATCH] * lisp/subr.el (apply-partially): Use a non-nil static environment. (--dolist-tail--, --dotimes-limit--): Don't declare dynamically bound. (dolist): Use a more efficient form for lexical-binding. (dotimes): Use a cleaner semantics for lexical-binding. * lisp/emacs-lisp/edebug.el (edebug-eval-top-level-form): Use eval-sexp-add-defvars. --- lisp/ChangeLog | 10 ++++++ lisp/emacs-lisp/edebug.el | 3 +- lisp/subr.el | 65 ++++++++++++++++++++++++++------------- src/lread.c | 1 + 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c1e12152f1..b517c48738 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,13 @@ +2011-03-30 Stefan Monnier + + * subr.el (apply-partially): Use a non-nil static environment. + (--dolist-tail--, --dotimes-limit--): Don't declare dynamically bound. + (dolist): Use a more efficient form for lexical-binding. + (dotimes): Use a cleaner semantics for lexical-binding. + + * emacs-lisp/edebug.el (edebug-eval-top-level-form): + Use eval-sexp-add-defvars. + 2011-03-30 Juanma Barranquero * makefile.w32-in (COMPILE_FIRST): Remove pcase. diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index dfc268421e..8135b5c4f2 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el @@ -566,7 +566,8 @@ already is one.)" ;; but this causes problems while edebugging edebug. (let ((edebug-all-forms t) (edebug-all-defs t)) - (edebug-read-top-level-form)))) + (eval-sexp-add-defvars + (edebug-read-top-level-form))))) (defun edebug-read-top-level-form () diff --git a/lisp/subr.el b/lisp/subr.el index c5fedae2bf..205828b416 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -124,7 +124,7 @@ ARGS is a list of the first N arguments to pass to FUN. The result is a new function which does the same as FUN, except that the first N arguments are fixed at the values with which this function was called." - `(closure () (&rest args) + `(closure (t) (&rest args) (apply ',fun ,@(mapcar (lambda (arg) `',arg) args) args))) (if (null (featurep 'cl)) @@ -174,8 +174,6 @@ value of last one, or nil if there are none. ;; If we reload subr.el after having loaded CL, be careful not to ;; overwrite CL's extended definition of `dolist', `dotimes', ;; `declare', `push' and `pop'. -(defvar --dolist-tail-- nil - "Temporary variable used in `dolist' expansion.") (defmacro dolist (spec &rest body) "Loop over a list. @@ -189,19 +187,27 @@ Then evaluate RESULT to get return value, default nil. ;; use dolist. ;; FIXME: This cost disappears in byte-compiled lexical-binding files. (let ((temp '--dolist-tail--)) - `(let ((,temp ,(nth 1 spec)) - ,(car spec)) - (while ,temp - ;; FIXME: In lexical-binding code, a `let' inside the loop might - ;; turn out to be faster than the an outside `let' this `setq'. - (setq ,(car spec) (car ,temp)) - ,@body - (setq ,temp (cdr ,temp))) - ,@(if (cdr (cdr spec)) - `((setq ,(car spec) nil) ,@(cdr (cdr spec))))))) - -(defvar --dotimes-limit-- nil - "Temporary variable used in `dotimes' expansion.") + ;; This is not a reliable test, but it does not matter because both + ;; semantics are acceptable, tho 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)))) + ,@(if (cdr (cdr spec)) + ;; FIXME: This let often leads to "unused var" warnings. + `((let ((,(car spec) nil)) ,@(cdr (cdr spec)))))) + `(let ((,temp ,(nth 1 spec)) + ,(car spec)) + (while ,temp + (setq ,(car spec) (car ,temp)) + ,@body + (setq ,temp (cdr ,temp))) + ,@(if (cdr (cdr spec)) + `((setq ,(car spec) nil) ,@(cdr (cdr spec)))))))) (defmacro dotimes (spec &rest body) "Loop a certain number of times. @@ -214,15 +220,30 @@ the return value (nil if RESULT is omitted). ;; 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))) - `(let ((,temp ,end) - (,(car spec) ,start)) - (while (< ,(car spec) ,temp) - ,@body - (setq ,(car spec) (1+ ,(car spec)))) - ,@(cdr (cdr spec))))) + ;; This is not a reliable test, but it does not matter because both + ;; semantics are acceptable, tho 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)))))) (defmacro declare (&rest specs) "Do not evaluate any arguments and return nil. diff --git a/src/lread.c b/src/lread.c index 7a8d7cf9a6..2418353252 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1889,6 +1889,7 @@ which is the input stream for reading characters. This function does not move point. */) (Lisp_Object start, Lisp_Object end, Lisp_Object printflag, Lisp_Object read_function) { + /* FIXME: Do the eval-sexp-add-defvars danse! */ int count = SPECPDL_INDEX (); Lisp_Object tem, cbuf; -- 2.20.1