diff options
| -rw-r--r-- | lisp/ChangeLog | 22 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-lexbind.el | 18 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 4 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cconv.el | 362 | ||||
| -rw-r--r-- | lisp/emacs-lisp/macroexp.el | 13 |
5 files changed, 214 insertions, 205 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 7c920b2eadc..6a47a2626a5 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,25 @@ | |||
| 1 | 2011-02-11 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/bytecomp.el (byte-compile-lambda): Fix `fun' that was not | ||
| 4 | renamed to `bytecomp-fun'. | ||
| 5 | |||
| 6 | * emacs-lisp/byte-lexbind.el (byte-compile-lforminfo-analyze): | ||
| 7 | Understand the :fun-body case for catch, save-window-excursion, and | ||
| 8 | condition-case. | ||
| 9 | (byte-compile-maybe-push-heap-environment): No need when nclosures is | ||
| 10 | zero and byte-compile-current-num-closures is -1. | ||
| 11 | |||
| 12 | * emacs-lisp/cconv.el (cconv-not-lexical-var-p): New function. | ||
| 13 | (cconv-freevars): Use it. | ||
| 14 | (cconv-closure-convert-rec): Avoid `position'. | ||
| 15 | (cconv-analyse-function): New function. | ||
| 16 | (cconv-analyse-form): Use it. `inclosure' can't be nil any more. | ||
| 17 | Check lexical vars at let-binding time rather than when referenced. | ||
| 18 | For defuns to be in an empty environment and lambdas to take lexical args. | ||
| 19 | Pay attention to the need to build closures in catch, unwind-protect, | ||
| 20 | save-window-excursion, condition-case, and track-mouse. | ||
| 21 | Fix defconst/defvar handling. | ||
| 22 | |||
| 1 | 2011-02-10 Stefan Monnier <monnier@iro.umontreal.ca> | 23 | 2011-02-10 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 24 | ||
| 3 | * emacs-lisp/cconv.el (cconv-mutated, cconv-captured) | 25 | * emacs-lisp/cconv.el (cconv-mutated, cconv-captured) |
diff --git a/lisp/emacs-lisp/byte-lexbind.el b/lisp/emacs-lisp/byte-lexbind.el index df463c17549..313c4b6ad0f 100644 --- a/lisp/emacs-lisp/byte-lexbind.el +++ b/lisp/emacs-lisp/byte-lexbind.el | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | ;;; byte-lexbind.el --- Lexical binding support for byte-compiler | 1 | ;;; byte-lexbind.el --- Lexical binding support for byte-compiler |
| 2 | ;; | 2 | ;; |
| 3 | ;; Copyright (C) 2001, 2002, 2010 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2001, 2002, 2010, 2011 Free Software Foundation, Inc. |
| 4 | ;; | 4 | ;; |
| 5 | ;; Author: Miles Bader <miles@gnu.org> | 5 | ;; Author: Miles Bader <miles@gnu.org> |
| 6 | ;; Keywords: lisp, compiler, lexical binding | 6 | ;; Keywords: lisp, compiler, lexical binding |
| @@ -202,24 +202,25 @@ LFORMINFO." | |||
| 202 | (byte-compile-lvarinfo-note-set vinfo) | 202 | (byte-compile-lvarinfo-note-set vinfo) |
| 203 | (byte-compile-lforminfo-note-closure lforminfo vinfo | 203 | (byte-compile-lforminfo-note-closure lforminfo vinfo |
| 204 | closure-flag))))))) | 204 | closure-flag))))))) |
| 205 | ((eq fun 'catch) | 205 | ((and (eq fun 'catch) (not (eq :fun-body (nth 2 form)))) |
| 206 | ;; tag | 206 | ;; tag |
| 207 | (byte-compile-lforminfo-analyze lforminfo (cadr form) | 207 | (byte-compile-lforminfo-analyze lforminfo (cadr form) |
| 208 | ignore closure-flag) | 208 | ignore closure-flag) |
| 209 | ;; `catch' uses a closure for the body | 209 | ;; `catch' uses a closure for the body |
| 210 | (byte-compile-lforminfo-analyze-forms | 210 | (byte-compile-lforminfo-analyze-forms |
| 211 | lforminfo form 2 | 211 | lforminfo form 2 |
| 212 | ignore | 212 | ignore |
| 213 | (or closure-flag | 213 | (or closure-flag |
| 214 | (and (not byte-compile-use-downward-closures) | 214 | (and (not byte-compile-use-downward-closures) |
| 215 | (byte-compile-lforminfo-make-closure-flag))))) | 215 | (byte-compile-lforminfo-make-closure-flag))))) |
| 216 | ((eq fun 'cond) | 216 | ((eq fun 'cond) |
| 217 | (byte-compile-lforminfo-analyze-clauses lforminfo (cdr form) 0 | 217 | (byte-compile-lforminfo-analyze-clauses lforminfo (cdr form) 0 |
| 218 | ignore closure-flag)) | 218 | ignore closure-flag)) |
| 219 | ((eq fun 'condition-case) | 219 | ((eq fun 'condition-case) |
| 220 | ;; `condition-case' separates its body/handlers into | 220 | ;; `condition-case' separates its body/handlers into |
| 221 | ;; separate closures. | 221 | ;; separate closures. |
| 222 | (unless (or closure-flag byte-compile-use-downward-closures) | 222 | (unless (or (eq (nth 1 form) :fun-body) |
| 223 | closure-flag byte-compile-use-downward-closures) | ||
| 223 | ;; condition case is implemented by calling a function | 224 | ;; condition case is implemented by calling a function |
| 224 | (setq closure-flag (byte-compile-lforminfo-make-closure-flag))) | 225 | (setq closure-flag (byte-compile-lforminfo-make-closure-flag))) |
| 225 | ;; value form | 226 | ;; value form |
| @@ -281,7 +282,8 @@ LFORMINFO." | |||
| 281 | ((eq fun 'quote) | 282 | ((eq fun 'quote) |
| 282 | ;; do nothing | 283 | ;; do nothing |
| 283 | ) | 284 | ) |
| 284 | ((eq fun 'save-window-excursion) | 285 | ((and (eq fun 'save-window-excursion) |
| 286 | (not (eq :fun-body (nth 1 form)))) | ||
| 285 | ;; `save-window-excursion' currently uses a funny implementation | 287 | ;; `save-window-excursion' currently uses a funny implementation |
| 286 | ;; that requires its body forms be put into a closure (it should | 288 | ;; that requires its body forms be put into a closure (it should |
| 287 | ;; be fixed to work more like `save-excursion' etc., do). | 289 | ;; be fixed to work more like `save-excursion' etc., do). |
| @@ -579,6 +581,7 @@ proper scope)." | |||
| 579 | (let ((nclosures | 581 | (let ((nclosures |
| 580 | (and lforminfo (byte-compile-lforminfo-num-closures lforminfo)))) | 582 | (and lforminfo (byte-compile-lforminfo-num-closures lforminfo)))) |
| 581 | (if (or (null lforminfo) | 583 | (if (or (null lforminfo) |
| 584 | (zerop nclosures) | ||
| 582 | (= nclosures byte-compile-current-num-closures)) | 585 | (= nclosures byte-compile-current-num-closures)) |
| 583 | ;; No need to push a heap environment. | 586 | ;; No need to push a heap environment. |
| 584 | nil | 587 | nil |
| @@ -692,5 +695,4 @@ binding slots have been popped." | |||
| 692 | 695 | ||
| 693 | (provide 'byte-lexbind) | 696 | (provide 'byte-lexbind) |
| 694 | 697 | ||
| 695 | ;;; arch-tag: b8f1dff6-9edb-4430-a96f-323d42a681a9 | ||
| 696 | ;;; byte-lexbind.el ends here | 698 | ;;; byte-lexbind.el ends here |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index e14ecc608c7..f37d7489e9a 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -2745,7 +2745,7 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2745 | ;; containing the args and any closed-over variables. | 2745 | ;; containing the args and any closed-over variables. |
| 2746 | (and lexical-binding | 2746 | (and lexical-binding |
| 2747 | (byte-compile-make-lambda-lexenv | 2747 | (byte-compile-make-lambda-lexenv |
| 2748 | fun | 2748 | bytecomp-fun |
| 2749 | byte-compile-lexical-environment))) | 2749 | byte-compile-lexical-environment))) |
| 2750 | (is-closure | 2750 | (is-closure |
| 2751 | ;; This is true if we should be making a closure instead of | 2751 | ;; This is true if we should be making a closure instead of |
| @@ -2804,7 +2804,7 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2804 | (let ((code (byte-compile-lambda form add-lambda))) | 2804 | (let ((code (byte-compile-lambda form add-lambda))) |
| 2805 | (if (byte-compile-closure-code-p code) | 2805 | (if (byte-compile-closure-code-p code) |
| 2806 | (byte-compile-make-closure code) | 2806 | (byte-compile-make-closure code) |
| 2807 | ;; A simple lambda is just a constant | 2807 | ;; A simple lambda is just a constant. |
| 2808 | (byte-compile-constant code)))) | 2808 | (byte-compile-constant code)))) |
| 2809 | 2809 | ||
| 2810 | (defun byte-compile-constants-vector () | 2810 | (defun byte-compile-constants-vector () |
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el index 60bc906b60c..af42a2864c9 100644 --- a/lisp/emacs-lisp/cconv.el +++ b/lisp/emacs-lisp/cconv.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; cconv.el --- Closure conversion for statically scoped Emacs lisp. -*- lexical-binding: t -*- | 1 | ;;; cconv.el --- Closure conversion for statically scoped Emacs lisp. -*- lexical-binding: nil -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2011 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2011 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -82,8 +82,19 @@ is less than this number.") | |||
| 82 | (defvar cconv-captured+mutated nil | 82 | (defvar cconv-captured+mutated nil |
| 83 | "An intersection between cconv-mutated and cconv-captured lists.") | 83 | "An intersection between cconv-mutated and cconv-captured lists.") |
| 84 | (defvar cconv-lambda-candidates nil | 84 | (defvar cconv-lambda-candidates nil |
| 85 | "List of candidates for lambda lifting") | 85 | "List of candidates for lambda lifting. |
| 86 | 86 | Each candidate has the form (VAR INCLOSURE BINDER PARENTFORM).") | |
| 87 | |||
| 88 | (defun cconv-not-lexical-var-p (var) | ||
| 89 | (or (not (symbolp var)) ; form is not a list | ||
| 90 | (special-variable-p var) | ||
| 91 | ;; byte-compile-bound-variables normally holds both the | ||
| 92 | ;; dynamic and lexical vars, but the bytecomp.el should | ||
| 93 | ;; only call us at the top-level so there shouldn't be | ||
| 94 | ;; any lexical vars in it here. | ||
| 95 | (memq var byte-compile-bound-variables) | ||
| 96 | (memq var '(nil t)) | ||
| 97 | (keywordp var))) | ||
| 87 | 98 | ||
| 88 | (defun cconv-freevars (form &optional fvrs) | 99 | (defun cconv-freevars (form &optional fvrs) |
| 89 | "Find all free variables of given form. | 100 | "Find all free variables of given form. |
| @@ -166,24 +177,17 @@ Returns a list of free variables." | |||
| 166 | (append fvrs fvrs-1))) | 177 | (append fvrs fvrs-1))) |
| 167 | 178 | ||
| 168 | (`(,(and sym (or `defun `defconst `defvar)) . ,_) | 179 | (`(,(and sym (or `defun `defconst `defvar)) . ,_) |
| 169 | ;; we call cconv-freevars only for functions(lambdas) | 180 | ;; We call cconv-freevars only for functions(lambdas) |
| 170 | ;; defun, defconst, defvar are not allowed to be inside | 181 | ;; defun, defconst, defvar are not allowed to be inside |
| 171 | ;; a function(lambda) | 182 | ;; a function (lambda). |
| 183 | ;; FIXME: should be a byte-compile-report-error! | ||
| 172 | (error "Invalid form: %s inside a function" sym)) | 184 | (error "Invalid form: %s inside a function" sym)) |
| 173 | 185 | ||
| 174 | (`(,_ . ,body-forms) ; first element is a function or whatever | 186 | (`(,_ . ,body-forms) ; First element is (like) a function. |
| 175 | (dolist (exp body-forms) | 187 | (dolist (exp body-forms) |
| 176 | (setq fvrs (cconv-freevars exp fvrs))) fvrs) | 188 | (setq fvrs (cconv-freevars exp fvrs))) fvrs) |
| 177 | 189 | ||
| 178 | (_ (if (or (not (symbolp form)) ; form is not a list | 190 | (_ (if (cconv-not-lexical-var-p form) |
| 179 | (special-variable-p form) | ||
| 180 | ;; byte-compile-bound-variables normally holds both the | ||
| 181 | ;; dynamic and lexical vars, but the bytecomp.el should | ||
| 182 | ;; only call us at the top-level so there shouldn't be | ||
| 183 | ;; any lexical vars in it here. | ||
| 184 | (memq form byte-compile-bound-variables) | ||
| 185 | (memq form '(nil t)) | ||
| 186 | (keywordp form)) | ||
| 187 | fvrs | 191 | fvrs |
| 188 | (cons form fvrs))))) | 192 | (cons form fvrs))))) |
| 189 | 193 | ||
| @@ -200,12 +204,13 @@ Returns a list of free variables." | |||
| 200 | -- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST | 204 | -- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST |
| 201 | 205 | ||
| 202 | Returns a form where all lambdas don't have any free variables." | 206 | Returns a form where all lambdas don't have any free variables." |
| 207 | (message "Entering cconv-closure-convert...") | ||
| 203 | (let ((cconv-mutated '()) | 208 | (let ((cconv-mutated '()) |
| 204 | (cconv-lambda-candidates '()) | 209 | (cconv-lambda-candidates '()) |
| 205 | (cconv-captured '()) | 210 | (cconv-captured '()) |
| 206 | (cconv-captured+mutated '())) | 211 | (cconv-captured+mutated '())) |
| 207 | ;; Analyse form - fill these variables with new information | 212 | ;; Analyse form - fill these variables with new information |
| 208 | (cconv-analyse-form form '() nil) | 213 | (cconv-analyse-form form '() 0) |
| 209 | ;; Calculate an intersection of cconv-mutated and cconv-captured | 214 | ;; Calculate an intersection of cconv-mutated and cconv-captured |
| 210 | (dolist (mvr cconv-mutated) | 215 | (dolist (mvr cconv-mutated) |
| 211 | (when (memq mvr cconv-captured) ; | 216 | (when (memq mvr cconv-captured) ; |
| @@ -271,7 +276,7 @@ Returns a form where all lambdas don't have any free variables." | |||
| 271 | 276 | ||
| 272 | (dolist (elm varsvalues) ;begin of dolist over varsvalues | 277 | (dolist (elm varsvalues) ;begin of dolist over varsvalues |
| 273 | (let (var value elm-new iscandidate ismutated) | 278 | (let (var value elm-new iscandidate ismutated) |
| 274 | (if (listp elm) ; (let (v1) ...) => (let ((v1 nil)) ...) | 279 | (if (consp elm) ; (let (v1) ...) => (let ((v1 nil)) ...) |
| 275 | (progn | 280 | (progn |
| 276 | (setq var (car elm)) | 281 | (setq var (car elm)) |
| 277 | (setq value (cadr elm))) | 282 | (setq value (cadr elm))) |
| @@ -430,9 +435,7 @@ Returns a form where all lambdas don't have any free variables." | |||
| 430 | (letbinds '()) | 435 | (letbinds '()) |
| 431 | (fvrs-new)) ; list of (closed-var var) | 436 | (fvrs-new)) ; list of (closed-var var) |
| 432 | (dolist (elm varsvalues) | 437 | (dolist (elm varsvalues) |
| 433 | (if (listp elm) | 438 | (setq var (if (consp elm) (car elm) elm)) |
| 434 | (setq var (car elm)) | ||
| 435 | (setq var elm)) | ||
| 436 | 439 | ||
| 437 | (let ((lmenvs-1 lmenvs)) ; just to avoid manipulating | 440 | (let ((lmenvs-1 lmenvs)) ; just to avoid manipulating |
| 438 | (dolist (lmenv lmenvs-1) ; the counter inside the loop | 441 | (dolist (lmenv lmenvs-1) ; the counter inside the loop |
| @@ -490,7 +493,7 @@ Returns a form where all lambdas don't have any free variables." | |||
| 490 | (`(quote . ,_) form) ; quote form | 493 | (`(quote . ,_) form) ; quote form |
| 491 | 494 | ||
| 492 | (`(function . ((lambda ,vars . ,body-forms))) ; function form | 495 | (`(function . ((lambda ,vars . ,body-forms))) ; function form |
| 493 | (let (fvrs-new) ; we remove vars from fvrs | 496 | (let (fvrs-new) ; we remove vars from fvrs |
| 494 | (dolist (elm fvrs) ;i use such a tricky way to avoid side effects | 497 | (dolist (elm fvrs) ;i use such a tricky way to avoid side effects |
| 495 | (when (not (memq elm vars)) | 498 | (when (not (memq elm vars)) |
| 496 | (push elm fvrs-new))) | 499 | (push elm fvrs-new))) |
| @@ -577,7 +580,7 @@ Returns a form where all lambdas don't have any free variables." | |||
| 577 | (`(,(and sym (or `defun `defmacro)) | 580 | (`(,(and sym (or `defun `defmacro)) |
| 578 | ,func ,vars . ,body-forms) | 581 | ,func ,vars . ,body-forms) |
| 579 | (if defs-are-legal | 582 | (if defs-are-legal |
| 580 | (let ((body-new '()) ; the whole body | 583 | (let ((body-new '()) ; the whole body |
| 581 | (body-forms-new '()) ; body w\o docstring and interactive | 584 | (body-forms-new '()) ; body w\o docstring and interactive |
| 582 | (letbind '())) | 585 | (letbind '())) |
| 583 | ; find mutable arguments | 586 | ; find mutable arguments |
| @@ -592,12 +595,11 @@ Returns a form where all lambdas don't have any free variables." | |||
| 592 | (when ismutated | 595 | (when ismutated |
| 593 | (push elm letbind) | 596 | (push elm letbind) |
| 594 | (push elm emvrs)))) | 597 | (push elm emvrs)))) |
| 595 | ;transform body-forms | 598 | ;transform body-forms |
| 596 | (when (stringp (car body-forms)) ; treat docstring well | 599 | (when (stringp (car body-forms)) ; treat docstring well |
| 597 | (push (car body-forms) body-new) | 600 | (push (car body-forms) body-new) |
| 598 | (setq body-forms (cdr body-forms))) | 601 | (setq body-forms (cdr body-forms))) |
| 599 | (when (and (listp (car body-forms)) ; treat (interactive) well | 602 | (when (eq (car-safe (car body-forms)) 'interactive) |
| 600 | (eq (caar body-forms) 'interactive)) | ||
| 601 | (push | 603 | (push |
| 602 | (cconv-closure-convert-rec | 604 | (cconv-closure-convert-rec |
| 603 | (car body-forms) | 605 | (car body-forms) |
| @@ -707,201 +709,171 @@ Returns a form where all lambdas don't have any free variables." | |||
| 707 | `(,func . ,body-forms-new))) | 709 | `(,func . ,body-forms-new))) |
| 708 | 710 | ||
| 709 | (_ | 711 | (_ |
| 710 | (if (memq form fvrs) ;form is a free variable | 712 | (let ((free (memq form fvrs))) |
| 711 | (let* ((numero (position form envs)) | 713 | (if free ;form is a free variable |
| 712 | (var '())) | 714 | (let* ((numero (- (length fvrs) (length free))) |
| 713 | (assert numero) | 715 | (var '())) |
| 714 | (if (null (cdr envs)) | 716 | (assert numero) |
| 715 | (setq var 'env) | 717 | (if (null (cdr envs)) |
| 718 | (setq var 'env) | ||
| 716 | ;replace form => | 719 | ;replace form => |
| 717 | ;(aref env #) | 720 | ;(aref env #) |
| 718 | (setq var `(aref env ,numero))) | 721 | (setq var `(aref env ,numero))) |
| 719 | (if (memq form emvrs) ; form => (car (aref env #)) if mutable | 722 | (if (memq form emvrs) ; form => (car (aref env #)) if mutable |
| 720 | `(car ,var) | 723 | `(car ,var) |
| 721 | var)) | 724 | var)) |
| 722 | (if (memq form emvrs) ; if form is a mutable variable | 725 | (if (memq form emvrs) ; if form is a mutable variable |
| 723 | `(car ,form) ; replace form => (car form) | 726 | `(car ,form) ; replace form => (car form) |
| 724 | form))))) | 727 | form)))))) |
| 725 | 728 | ||
| 726 | (defun cconv-analyse-form (form vars inclosure) | 729 | (defun cconv-analyse-function (args body env parentform inclosure) |
| 727 | 730 | (dolist (arg args) | |
| 731 | (cond | ||
| 732 | ((cconv-not-lexical-var-p arg) | ||
| 733 | (byte-compile-report-error | ||
| 734 | (format "Argument %S is not a lexical variable" arg))) | ||
| 735 | ((eq ?& (aref (symbol-name arg) 0)) nil) ;Ignore &rest, &optional, ... | ||
| 736 | (t (push (list arg inclosure parentform) env)))) ;Push vrs to vars. | ||
| 737 | (dolist (form body) ;Analyse body forms. | ||
| 738 | (cconv-analyse-form form env inclosure))) | ||
| 739 | |||
| 740 | (defun cconv-analyse-form (form env inclosure) | ||
| 728 | "Find mutated variables and variables captured by closure. Analyse | 741 | "Find mutated variables and variables captured by closure. Analyse |
| 729 | lambdas if they are suitable for lambda lifting. | 742 | lambdas if they are suitable for lambda lifting. |
| 730 | -- FORM is a piece of Elisp code after macroexpansion. | 743 | -- FORM is a piece of Elisp code after macroexpansion. |
| 731 | -- MLCVRS is a structure that contains captured and mutated variables. | 744 | -- ENV is a list of variables visible in current lexical environment. |
| 732 | (first MLCVRS) is a list of mutated variables, (second MLCVRS) is a | 745 | Each entry has the form (VAR INCLOSURE BINDER PARENTFORM) |
| 733 | list of candidates for lambda lifting and (third MLCVRS) is a list of | 746 | for let-bound vars and (VAR INCLOSURE PARENTFORM) for function arguments. |
| 734 | variables captured by closure. It should be (nil nil nil) initially. | 747 | -- INCLOSURE is the nesting level within lambdas." |
| 735 | -- VARS is a list of local variables visible in current environment | ||
| 736 | (initially empty). | ||
| 737 | -- INCLOSURE is a boolean variable, true if we are in closure. | ||
| 738 | Initially false" | ||
| 739 | (pcase form | 748 | (pcase form |
| 740 | ; let special form | 749 | ; let special form |
| 741 | (`(,(and (or `let* `let) letsym) ,varsvalues . ,body-forms) | 750 | (`(,(and (or `let* `let) letsym) ,binders . ,body-forms) |
| 742 | |||
| 743 | (when (eq letsym 'let) | ||
| 744 | (dolist (elm varsvalues) ; analyse values | ||
| 745 | (when (listp elm) | ||
| 746 | (cconv-analyse-form (cadr elm) vars inclosure)))) | ||
| 747 | 751 | ||
| 748 | (let ((v nil) | 752 | (let ((orig-env env) |
| 749 | (var nil) | 753 | (var nil) |
| 750 | (value nil) | 754 | (value nil)) |
| 751 | (varstruct nil)) | 755 | (dolist (binder binders) |
| 752 | (dolist (elm varsvalues) | 756 | (if (not (consp binder)) |
| 753 | (if (listp elm) | ||
| 754 | (progn | 757 | (progn |
| 755 | (setq var (car elm)) | 758 | (setq var binder) ; treat the form (let (x) ...) well |
| 756 | (setq value (cadr elm))) | 759 | (setq value nil)) |
| 757 | (progn | 760 | (setq var (car binder)) |
| 758 | (setq var elm) ; treat the form (let (x) ...) well | 761 | (setq value (cadr binder)) |
| 759 | (setq value nil))) | 762 | |
| 760 | 763 | (cconv-analyse-form value (if (eq letsym 'let*) env orig-env) | |
| 761 | (when (eq letsym 'let*) ; analyse value | 764 | inclosure)) |
| 762 | (cconv-analyse-form value vars inclosure)) | 765 | |
| 763 | 766 | (unless (cconv-not-lexical-var-p var) | |
| 764 | (let (vars-new) ; remove the old var | 767 | (let ((varstruct (list var inclosure binder form))) |
| 765 | (dolist (vr vars) | 768 | (push varstruct env) ; Push a new one. |
| 766 | (when (not (eq (car vr) var)) | 769 | |
| 767 | (push vr vars-new))) | 770 | (pcase value |
| 768 | (setq vars vars-new)) | 771 | (`(function (lambda . ,_)) |
| 769 | 772 | ;; If var is a function push it to lambda list. | |
| 770 | (setq varstruct (list var inclosure elm form)) | 773 | (push varstruct cconv-lambda-candidates))))))) |
| 771 | (push varstruct vars) ; push a new one | 774 | |
| 772 | 775 | (dolist (form body-forms) ; Analyse body forms. | |
| 773 | (when (and (listp value) | 776 | (cconv-analyse-form form env inclosure))) |
| 774 | (eq (car value) 'function) | 777 | |
| 775 | (eq (caadr value) 'lambda)) | ||
| 776 | ; if var is a function | ||
| 777 | ; push it to lambda list | ||
| 778 | (push varstruct cconv-lambda-candidates)))) | ||
| 779 | |||
| 780 | (dolist (elm body-forms) ; analyse body forms | ||
| 781 | (cconv-analyse-form elm vars inclosure)) | ||
| 782 | nil) | ||
| 783 | ; defun special form | 778 | ; defun special form |
| 784 | (`(,(or `defun `defmacro) ,func ,vrs . ,body-forms) | 779 | (`(,(or `defun `defmacro) ,func ,vrs . ,body-forms) |
| 785 | (let ((v nil)) | 780 | (when env |
| 786 | (dolist (vr vrs) | 781 | (byte-compile-log-warning |
| 787 | (push (list vr form) vars))) ;push vrs to vars | 782 | (format "Function %S will ignore its context %S" |
| 788 | (dolist (elm body-forms) ; analyse body forms | 783 | func (mapcar #'car env)) |
| 789 | (cconv-analyse-form elm vars inclosure)) | 784 | t :warning)) |
| 790 | nil) | 785 | (cconv-analyse-function vrs body-forms nil form 0)) |
| 791 | 786 | ||
| 792 | (`(function . ((lambda ,vrs . ,body-forms))) | 787 | (`(function (lambda ,vrs . ,body-forms)) |
| 793 | (if inclosure ;we are in closure | 788 | (cconv-analyse-function vrs body-forms env form (1+ inclosure))) |
| 794 | (setq inclosure (+ inclosure 1)) | 789 | |
| 795 | (setq inclosure 1)) | 790 | (`(setq . ,forms) |
| 796 | (let (vars-new) ; update vars | 791 | ;; If a local variable (member of env) is modified by setq then |
| 797 | (dolist (vr vars) ; we do that in such a tricky way | 792 | ;; it is a mutated variable. |
| 798 | (when (not (memq (car vr) vrs)) ; to avoid side effects | ||
| 799 | (push vr vars-new))) | ||
| 800 | (dolist (vr vrs) | ||
| 801 | (push (list vr inclosure form) vars-new)) | ||
| 802 | (setq vars vars-new)) | ||
| 803 | |||
| 804 | (dolist (elm body-forms) | ||
| 805 | (cconv-analyse-form elm vars inclosure)) | ||
| 806 | nil) | ||
| 807 | |||
| 808 | (`(setq . ,forms) ; setq | ||
| 809 | ; if a local variable (member of vars) | ||
| 810 | ; is modified by setq | ||
| 811 | ; then it is a mutated variable | ||
| 812 | (while forms | 793 | (while forms |
| 813 | (let ((v (assq (car forms) vars))) ; v = non nil if visible | 794 | (let ((v (assq (car forms) env))) ; v = non nil if visible |
| 814 | (when v | 795 | (when v |
| 815 | (push v cconv-mutated) | 796 | (push v cconv-mutated) |
| 816 | ;; delete from candidate list for lambda lifting | 797 | ;; Delete from candidate list for lambda lifting. |
| 817 | (setq cconv-lambda-candidates (delq v cconv-lambda-candidates)) | 798 | (setq cconv-lambda-candidates (delq v cconv-lambda-candidates)) |
| 818 | (when inclosure | 799 | (unless (eq inclosure (cadr v)) ;Bound in a different closure level. |
| 819 | ;; test if v is declared as argument for lambda | 800 | (push v cconv-captured)))) |
| 820 | (let* ((thirdv (third v)) | 801 | (cconv-analyse-form (cadr forms) env inclosure) |
| 821 | (isarg (if (listp thirdv) | 802 | (setq forms (cddr forms)))) |
| 822 | (eq (car thirdv) 'function) nil))) | 803 | |
| 823 | (if isarg | 804 | (`((lambda . ,_) . ,_) ; first element is lambda expression |
| 824 | (when (> inclosure (cadr v)) ; when we are in closure | ||
| 825 | (push v cconv-captured)) ; push it to captured vars | ||
| 826 | ;; FIXME more detailed comments needed | ||
| 827 | (push v cconv-captured)))))) | ||
| 828 | (cconv-analyse-form (cadr forms) vars inclosure) | ||
| 829 | (setq forms (cddr forms))) | ||
| 830 | nil) | ||
| 831 | |||
| 832 | (`((lambda . ,_) . ,_) ; first element is lambda expression | ||
| 833 | (dolist (exp `((function ,(car form)) . ,(cdr form))) | 805 | (dolist (exp `((function ,(car form)) . ,(cdr form))) |
| 834 | (cconv-analyse-form exp vars inclosure)) | 806 | (cconv-analyse-form exp env inclosure))) |
| 835 | nil) | ||
| 836 | 807 | ||
| 837 | (`(cond . ,cond-forms) ; cond special form | 808 | (`(cond . ,cond-forms) ; cond special form |
| 838 | (dolist (exp1 cond-forms) | 809 | (dolist (forms cond-forms) |
| 839 | (dolist (exp2 exp1) | 810 | (dolist (form forms) |
| 840 | (cconv-analyse-form exp2 vars inclosure))) | 811 | (cconv-analyse-form form env inclosure)))) |
| 841 | nil) | ||
| 842 | 812 | ||
| 843 | (`(quote . ,_) nil) ; quote form | 813 | (`(quote . ,_) nil) ; quote form |
| 844 | |||
| 845 | (`(function . ,_) nil) ; same as quote | 814 | (`(function . ,_) nil) ; same as quote |
| 846 | 815 | ||
| 847 | (`(condition-case ,var ,protected-form . ,conditions-bodies) | 816 | (`(condition-case ,var ,protected-form . ,handlers) |
| 848 | ;condition-case | 817 | ;; FIXME: The bytecode for condition-case forces us to wrap the |
| 849 | (cconv-analyse-form protected-form vars inclosure) | 818 | ;; form and handlers in closures (for handlers, it's probably |
| 850 | (dolist (exp conditions-bodies) | 819 | ;; unavoidable, but not for the protected form). |
| 851 | (cconv-analyse-form (cadr exp) vars inclosure)) | 820 | (setq inclosure (1+ inclosure)) |
| 852 | nil) | 821 | (cconv-analyse-form protected-form env inclosure) |
| 853 | 822 | (push (list var inclosure form) env) | |
| 854 | (`(,(or `defconst `defvar) ,value) | 823 | (dolist (handler handlers) |
| 855 | (cconv-analyse-form value vars inclosure)) | 824 | (dolist (form (cdr handler)) |
| 825 | (cconv-analyse-form form env inclosure)))) | ||
| 826 | |||
| 827 | ;; FIXME: The bytecode for catch forces us to wrap the body. | ||
| 828 | (`(,(or `catch `unwind-protect) ,form . ,body) | ||
| 829 | (cconv-analyse-form form env inclosure) | ||
| 830 | (setq inclosure (1+ inclosure)) | ||
| 831 | (dolist (form body) | ||
| 832 | (cconv-analyse-form form env inclosure))) | ||
| 833 | |||
| 834 | ;; FIXME: The bytecode for save-window-excursion and the lack of | ||
| 835 | ;; bytecode for track-mouse forces us to wrap the body. | ||
| 836 | (`(,(or `save-window-excursion `track-mouse) . ,body) | ||
| 837 | (setq inclosure (1+ inclosure)) | ||
| 838 | (dolist (form body) | ||
| 839 | (cconv-analyse-form form env inclosure))) | ||
| 840 | |||
| 841 | (`(,(or `defconst `defvar) ,var ,value . ,_) | ||
| 842 | (push var byte-compile-bound-variables) | ||
| 843 | (cconv-analyse-form value env inclosure)) | ||
| 856 | 844 | ||
| 857 | (`(,(or `funcall `apply) ,fun . ,args) | 845 | (`(,(or `funcall `apply) ,fun . ,args) |
| 858 | ;; Here we ignore fun because | 846 | ;; Here we ignore fun because funcall and apply are the only two |
| 859 | ;; funcall and apply are the only two | 847 | ;; functions where we can pass a candidate for lambda lifting as |
| 860 | ;; functions where we can pass a candidate | 848 | ;; argument. So, if we see fun elsewhere, we'll delete it from |
| 861 | ;; for lambda lifting as argument. | 849 | ;; lambda candidate list. |
| 862 | ;; So, if we see fun elsewhere, we'll | 850 | (if (symbolp fun) |
| 863 | ;; delete it from lambda candidate list. | 851 | (let ((lv (assq fun cconv-lambda-candidates))) |
| 864 | 852 | (when lv | |
| 865 | ;; If this funcall and the definition of fun | 853 | (unless (eq (cadr lv) inclosure) |
| 866 | ;; are in different closures - we delete fun from | 854 | (push lv cconv-captured) |
| 867 | ;; canidate list, because it is too complicated | 855 | ;; If this funcall and the definition of fun are in |
| 868 | ;; to manage free variables in this case. | 856 | ;; different closures - we delete fun from candidate |
| 869 | (let ((lv (assq fun cconv-lambda-candidates))) | 857 | ;; list, because it is too complicated to manage free |
| 870 | (when lv | 858 | ;; variables in this case. |
| 871 | (when (not (eq (cadr lv) inclosure)) | 859 | (setq cconv-lambda-candidates |
| 872 | (setq cconv-lambda-candidates | 860 | (delq lv cconv-lambda-candidates))))) |
| 873 | (delq lv cconv-lambda-candidates))))) | 861 | (cconv-analyse-form fun env inclosure)) |
| 874 | 862 | (dolist (form args) | |
| 875 | (dolist (elm args) | 863 | (cconv-analyse-form form env inclosure))) |
| 876 | (cconv-analyse-form elm vars inclosure)) | 864 | |
| 877 | nil) | 865 | (`(,_ . ,body-forms) ; First element is a function or whatever. |
| 878 | 866 | (dolist (form body-forms) | |
| 879 | (`(,_ . ,body-forms) ; first element is a function or whatever | 867 | (cconv-analyse-form form env inclosure))) |
| 880 | (dolist (exp body-forms) | 868 | |
| 881 | (cconv-analyse-form exp vars inclosure)) | 869 | ((pred symbolp) |
| 882 | nil) | 870 | (let ((dv (assq form env))) ; dv = declared and visible |
| 883 | 871 | (when dv | |
| 884 | (_ | 872 | (unless (eq inclosure (cadr dv)) ; capturing condition |
| 885 | (when (and (symbolp form) | 873 | (push dv cconv-captured)) |
| 886 | (not (memq form '(nil t))) | 874 | ;; Delete lambda if it is found here, since it escapes. |
| 887 | (not (keywordp form)) | 875 | (setq cconv-lambda-candidates |
| 888 | (not (special-variable-p form))) | 876 | (delq dv cconv-lambda-candidates))))))) |
| 889 | (let ((dv (assq form vars))) ; dv = declared and visible | ||
| 890 | (when dv | ||
| 891 | (when inclosure | ||
| 892 | ;; test if v is declared as argument of lambda | ||
| 893 | (let* ((thirddv (third dv)) | ||
| 894 | (isarg (if (listp thirddv) | ||
| 895 | (eq (car thirddv) 'function) nil))) | ||
| 896 | (if isarg | ||
| 897 | ;; FIXME add detailed comments | ||
| 898 | (when (> inclosure (cadr dv)) ; capturing condition | ||
| 899 | (push dv cconv-captured)) | ||
| 900 | (push dv cconv-captured)))) | ||
| 901 | ; delete lambda | ||
| 902 | (setq cconv-lambda-candidates ; if it is found here | ||
| 903 | (delq dv cconv-lambda-candidates))))) | ||
| 904 | nil))) | ||
| 905 | 877 | ||
| 906 | (provide 'cconv) | 878 | (provide 'cconv) |
| 907 | ;;; cconv.el ends here | 879 | ;;; cconv.el ends here |
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index af8047256e2..bccc60a24e0 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | 29 | ||
| 30 | ;;; Code: | 30 | ;;; Code: |
| 31 | 31 | ||
| 32 | (eval-when-compile (require 'cl)) | ||
| 33 | |||
| 32 | ;; Bound by the top-level `macroexpand-all', and modified to include any | 34 | ;; Bound by the top-level `macroexpand-all', and modified to include any |
| 33 | ;; macros defined by `defmacro'. | 35 | ;; macros defined by `defmacro'. |
| 34 | (defvar macroexpand-all-environment nil) | 36 | (defvar macroexpand-all-environment nil) |
| @@ -164,6 +166,17 @@ Assumes the caller has bound `macroexpand-all-environment'." | |||
| 164 | (cons (macroexpand-all-1 | 166 | (cons (macroexpand-all-1 |
| 165 | (list 'function f)) | 167 | (list 'function f)) |
| 166 | (macroexpand-all-forms args))))) | 168 | (macroexpand-all-forms args))))) |
| 169 | ;; Macro expand compiler macros. | ||
| 170 | ;; FIXME: Don't depend on CL. | ||
| 171 | (`(,(and (pred symbolp) fun | ||
| 172 | (guard (and (eq (get fun 'byte-compile) | ||
| 173 | 'cl-byte-compile-compiler-macro) | ||
| 174 | (functionp 'compiler-macroexpand)))) | ||
| 175 | . ,_) | ||
| 176 | (let ((newform (compiler-macroexpand form))) | ||
| 177 | (if (eq form newform) | ||
| 178 | (macroexpand-all-forms form 1) | ||
| 179 | (macroexpand-all-1 newform)))) | ||
| 167 | (`(,_ . ,_) | 180 | (`(,_ . ,_) |
| 168 | ;; For every other list, we just expand each argument (for | 181 | ;; For every other list, we just expand each argument (for |
| 169 | ;; setq/setq-default this works alright because the variable names | 182 | ;; setq/setq-default this works alright because the variable names |