diff options
| author | Stefan Monnier | 2011-02-10 18:37:03 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2011-02-10 18:37:03 -0500 |
| commit | d779e73c22ae9fedcf6edc6ec286f19cf2e3d89a (patch) | |
| tree | 099bd33135c87358e721ad3840cba1ff880ed804 | |
| parent | 94d11cb5773b3b37367ee3c4885a374ff129d475 (diff) | |
| download | emacs-d779e73c22ae9fedcf6edc6ec286f19cf2e3d89a.tar.gz emacs-d779e73c22ae9fedcf6edc6ec286f19cf2e3d89a.zip | |
* lisp/emacs-lisp/bytecomp.el (byte-compile-catch)
(byte-compile-unwind-protect, byte-compile-track-mouse)
(byte-compile-condition-case, byte-compile-save-window-excursion):
Provide a :fun-body alternative, so that info can be propagated from the
surrounding context, as is the case for lexical scoping.
* lisp/emacs-lisp/cconv.el (cconv-mutated, cconv-captured)
(cconv-captured+mutated, cconv-lambda-candidates): Fix up declaration.
(cconv-freevars): Minor cleanup. Fix handling of the error var in
condition-case.
| -rw-r--r-- | lisp/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 123 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cconv.el | 1528 |
3 files changed, 850 insertions, 814 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c137860013b..7c920b2eadc 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | 2011-02-10 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/cconv.el (cconv-mutated, cconv-captured) | ||
| 4 | (cconv-captured+mutated, cconv-lambda-candidates): Fix up declaration. | ||
| 5 | (cconv-freevars): Minor cleanup. Fix handling of the error var in | ||
| 6 | condition-case. | ||
| 7 | |||
| 8 | * emacs-lisp/bytecomp.el (byte-compile-catch) | ||
| 9 | (byte-compile-unwind-protect, byte-compile-track-mouse) | ||
| 10 | (byte-compile-condition-case, byte-compile-save-window-excursion): | ||
| 11 | Provide a :fun-body alternative, so that info can be propagated from the | ||
| 12 | surrounding context, as is the case for lexical scoping. | ||
| 13 | |||
| 1 | 2011-02-10 Igor Kuzmin <kuzminig@iro.umontreal.ca> | 14 | 2011-02-10 Igor Kuzmin <kuzminig@iro.umontreal.ca> |
| 2 | 15 | ||
| 3 | * emacs-lisp/cconv.el: New file. | 16 | * emacs-lisp/cconv.el: New file. |
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index b258524b45f..e14ecc608c7 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -2706,11 +2706,11 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2706 | byte-compile-bound-variables)) | 2706 | byte-compile-bound-variables)) |
| 2707 | (bytecomp-body (cdr (cdr bytecomp-fun))) | 2707 | (bytecomp-body (cdr (cdr bytecomp-fun))) |
| 2708 | (bytecomp-doc (if (stringp (car bytecomp-body)) | 2708 | (bytecomp-doc (if (stringp (car bytecomp-body)) |
| 2709 | (prog1 (car bytecomp-body) | 2709 | (prog1 (car bytecomp-body) |
| 2710 | ;; Discard the doc string | 2710 | ;; Discard the doc string |
| 2711 | ;; unless it is the last element of the body. | 2711 | ;; unless it is the last element of the body. |
| 2712 | (if (cdr bytecomp-body) | 2712 | (if (cdr bytecomp-body) |
| 2713 | (setq bytecomp-body (cdr bytecomp-body)))))) | 2713 | (setq bytecomp-body (cdr bytecomp-body)))))) |
| 2714 | (bytecomp-int (assq 'interactive bytecomp-body))) | 2714 | (bytecomp-int (assq 'interactive bytecomp-body))) |
| 2715 | ;; Process the interactive spec. | 2715 | ;; Process the interactive spec. |
| 2716 | (when bytecomp-int | 2716 | (when bytecomp-int |
| @@ -4076,76 +4076,79 @@ if LFORMINFO is nil (meaning all bindings are dynamic)." | |||
| 4076 | 4076 | ||
| 4077 | (defun byte-compile-catch (form) | 4077 | (defun byte-compile-catch (form) |
| 4078 | (byte-compile-form (car (cdr form))) | 4078 | (byte-compile-form (car (cdr form))) |
| 4079 | (byte-compile-push-constant | 4079 | (pcase (cddr form) |
| 4080 | (byte-compile-top-level (cons 'progn (cdr (cdr form))) for-effect)) | 4080 | (`(:fun-body ,f) |
| 4081 | (byte-compile-form `(list 'funcall ,f))) | ||
| 4082 | (body | ||
| 4083 | (byte-compile-push-constant | ||
| 4084 | (byte-compile-top-level (cons 'progn body) for-effect)))) | ||
| 4081 | (byte-compile-out 'byte-catch 0)) | 4085 | (byte-compile-out 'byte-catch 0)) |
| 4082 | 4086 | ||
| 4083 | (defun byte-compile-unwind-protect (form) | 4087 | (defun byte-compile-unwind-protect (form) |
| 4084 | (byte-compile-push-constant | 4088 | (pcase (cddr form) |
| 4085 | (byte-compile-top-level-body (cdr (cdr form)) t)) | 4089 | (`(:fun-body ,f) |
| 4090 | (byte-compile-form `(list (list 'funcall ,f)))) | ||
| 4091 | (handlers | ||
| 4092 | (byte-compile-push-constant | ||
| 4093 | (byte-compile-top-level-body handlers t)))) | ||
| 4086 | (byte-compile-out 'byte-unwind-protect 0) | 4094 | (byte-compile-out 'byte-unwind-protect 0) |
| 4087 | (byte-compile-form-do-effect (car (cdr form))) | 4095 | (byte-compile-form-do-effect (car (cdr form))) |
| 4088 | (byte-compile-out 'byte-unbind 1)) | 4096 | (byte-compile-out 'byte-unbind 1)) |
| 4089 | 4097 | ||
| 4090 | (defun byte-compile-track-mouse (form) | 4098 | (defun byte-compile-track-mouse (form) |
| 4091 | (byte-compile-form | 4099 | (byte-compile-form |
| 4092 | ;; Use quote rather that #' here, because we don't want to go | 4100 | (pcase form |
| 4093 | ;; through the body again, which would lead to an infinite recursion: | 4101 | (`(,_ :fun-body ,f) `(eval (list 'track-mouse (list 'funcall ,f)))) |
| 4094 | ;; "byte-compile-track-mouse" (0xbffc98e4) | 4102 | (_ `(eval '(track-mouse ,@(byte-compile-top-level-body (cdr form)))))))) |
| 4095 | ;; "byte-compile-form" (0xbffc9c54) | ||
| 4096 | ;; "byte-compile-top-level" (0xbffc9fd4) | ||
| 4097 | ;; "byte-compile-lambda" (0xbffca364) | ||
| 4098 | ;; "byte-compile-closure" (0xbffca6d4) | ||
| 4099 | ;; "byte-compile-function-form" (0xbffcaa44) | ||
| 4100 | ;; "byte-compile-form" (0xbffcadc0) | ||
| 4101 | ;; "mapc" (0xbffcaf74) | ||
| 4102 | ;; "byte-compile-funcall" (0xbffcb2e4) | ||
| 4103 | ;; "byte-compile-form" (0xbffcb654) | ||
| 4104 | ;; "byte-compile-track-mouse" (0xbffcb9d4) | ||
| 4105 | `(funcall '(lambda nil | ||
| 4106 | (track-mouse ,@(byte-compile-top-level-body (cdr form))))))) | ||
| 4107 | 4103 | ||
| 4108 | (defun byte-compile-condition-case (form) | 4104 | (defun byte-compile-condition-case (form) |
| 4109 | (let* ((var (nth 1 form)) | 4105 | (let* ((var (nth 1 form)) |
| 4110 | (byte-compile-bound-variables | 4106 | (byte-compile-bound-variables |
| 4111 | (if var (cons var byte-compile-bound-variables) | 4107 | (if var (cons var byte-compile-bound-variables) |
| 4112 | byte-compile-bound-variables))) | 4108 | byte-compile-bound-variables)) |
| 4109 | (fun-bodies (eq var :fun-body))) | ||
| 4113 | (byte-compile-set-symbol-position 'condition-case) | 4110 | (byte-compile-set-symbol-position 'condition-case) |
| 4114 | (unless (symbolp var) | 4111 | (unless (symbolp var) |
| 4115 | (byte-compile-warn | 4112 | (byte-compile-warn |
| 4116 | "`%s' is not a variable-name or nil (in condition-case)" var)) | 4113 | "`%s' is not a variable-name or nil (in condition-case)" var)) |
| 4114 | (if fun-bodies (setq var (make-symbol "err"))) | ||
| 4117 | (byte-compile-push-constant var) | 4115 | (byte-compile-push-constant var) |
| 4118 | (byte-compile-push-constant (byte-compile-top-level | 4116 | (if fun-bodies |
| 4119 | (nth 2 form) for-effect)) | 4117 | (byte-compile-form `(list 'funcall ,(nth 2 form))) |
| 4120 | (let ((clauses (cdr (cdr (cdr form)))) | 4118 | (byte-compile-push-constant |
| 4121 | compiled-clauses) | 4119 | (byte-compile-top-level (nth 2 form) for-effect))) |
| 4122 | (while clauses | 4120 | (let ((compiled-clauses |
| 4123 | (let* ((clause (car clauses)) | 4121 | (mapcar |
| 4124 | (condition (car clause))) | 4122 | (lambda (clause) |
| 4125 | (cond ((not (or (symbolp condition) | 4123 | (let ((condition (car clause))) |
| 4126 | (and (listp condition) | 4124 | (cond ((not (or (symbolp condition) |
| 4127 | (let ((syms condition) (ok t)) | 4125 | (and (listp condition) |
| 4128 | (while syms | 4126 | (let ((ok t)) |
| 4129 | (if (not (symbolp (car syms))) | 4127 | (dolist (sym condition) |
| 4130 | (setq ok nil)) | 4128 | (if (not (symbolp sym)) |
| 4131 | (setq syms (cdr syms))) | 4129 | (setq ok nil))) |
| 4132 | ok)))) | 4130 | ok)))) |
| 4133 | (byte-compile-warn | 4131 | (byte-compile-warn |
| 4134 | "`%s' is not a condition name or list of such (in condition-case)" | 4132 | "`%S' is not a condition name or list of such (in condition-case)" |
| 4135 | (prin1-to-string condition))) | 4133 | condition)) |
| 4136 | ;; ((not (or (eq condition 't) | 4134 | ;; (not (or (eq condition 't) |
| 4137 | ;; (and (stringp (get condition 'error-message)) | 4135 | ;; (and (stringp (get condition 'error-message)) |
| 4138 | ;; (consp (get condition 'error-conditions))))) | 4136 | ;; (consp (get condition |
| 4139 | ;; (byte-compile-warn | 4137 | ;; 'error-conditions))))) |
| 4140 | ;; "`%s' is not a known condition name (in condition-case)" | 4138 | ;; (byte-compile-warn |
| 4141 | ;; condition)) | 4139 | ;; "`%s' is not a known condition name |
| 4142 | ) | 4140 | ;; (in condition-case)" |
| 4143 | (push (cons condition | 4141 | ;; condition)) |
| 4144 | (byte-compile-top-level-body | 4142 | ) |
| 4145 | (cdr clause) for-effect)) | 4143 | (if fun-bodies |
| 4146 | compiled-clauses)) | 4144 | `(list ',condition (list 'funcall ,(cadr clause) ',var)) |
| 4147 | (setq clauses (cdr clauses))) | 4145 | (cons condition |
| 4148 | (byte-compile-push-constant (nreverse compiled-clauses))) | 4146 | (byte-compile-top-level-body |
| 4147 | (cdr clause) for-effect))))) | ||
| 4148 | (cdr (cdr (cdr form)))))) | ||
| 4149 | (if fun-bodies | ||
| 4150 | (byte-compile-form `(list ,@compiled-clauses)) | ||
| 4151 | (byte-compile-push-constant compiled-clauses))) | ||
| 4149 | (byte-compile-out 'byte-condition-case 0))) | 4152 | (byte-compile-out 'byte-condition-case 0))) |
| 4150 | 4153 | ||
| 4151 | 4154 | ||
| @@ -4168,8 +4171,12 @@ if LFORMINFO is nil (meaning all bindings are dynamic)." | |||
| 4168 | (byte-compile-out 'byte-unbind 1)) | 4171 | (byte-compile-out 'byte-unbind 1)) |
| 4169 | 4172 | ||
| 4170 | (defun byte-compile-save-window-excursion (form) | 4173 | (defun byte-compile-save-window-excursion (form) |
| 4171 | (byte-compile-push-constant | 4174 | (pcase (cdr form) |
| 4172 | (byte-compile-top-level-body (cdr form) for-effect)) | 4175 | (`(:fun-body ,f) |
| 4176 | (byte-compile-form `(list (list 'funcall ,f)))) | ||
| 4177 | (body | ||
| 4178 | (byte-compile-push-constant | ||
| 4179 | (byte-compile-top-level-body body for-effect)))) | ||
| 4173 | (byte-compile-out 'byte-save-window-excursion 0)) | 4180 | (byte-compile-out 'byte-save-window-excursion 0)) |
| 4174 | 4181 | ||
| 4175 | (defun byte-compile-with-output-to-temp-buffer (form) | 4182 | (defun byte-compile-with-output-to-temp-buffer (form) |
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el index ddcc7882d82..60bc906b60c 100644 --- a/lisp/emacs-lisp/cconv.el +++ b/lisp/emacs-lisp/cconv.el | |||
| @@ -1,77 +1,90 @@ | |||
| 1 | ;;; -*- lexical-binding: t -*- | 1 | ;;; cconv.el --- Closure conversion for statically scoped Emacs lisp. -*- lexical-binding: t -*- |
| 2 | ;;; cconv.el --- Closure conversion for statically scoped Emacs lisp. | ||
| 3 | 2 | ||
| 4 | ;; licence stuff will be added later(I don't know yet what to write here) | 3 | ;; Copyright (C) 2011 Free Software Foundation, Inc. |
| 4 | |||
| 5 | ;; Author: Igor Kuzmin <kzuminig@iro.umontreal.ca> | ||
| 6 | ;; Maintainer: FSF | ||
| 7 | ;; Keywords: lisp | ||
| 8 | ;; Package: emacs | ||
| 9 | |||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | |||
| 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 15 | ;; (at your option) any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | ||
| 5 | 24 | ||
| 6 | ;;; Commentary: | 25 | ;;; Commentary: |
| 7 | 26 | ||
| 8 | ;; This takes a piece of Elisp code, and eliminates all free variables from | 27 | ;; This takes a piece of Elisp code, and eliminates all free variables from |
| 9 | ;; lambda expressions. The user entry points are cconv-closure-convert and | 28 | ;; lambda expressions. The user entry points are cconv-closure-convert and |
| 10 | ;; cconv-closure-convert-toplevel(for toplevel forms). | 29 | ;; cconv-closure-convert-toplevel(for toplevel forms). |
| 11 | ;; All macros should be expanded. | 30 | ;; All macros should be expanded beforehand. |
| 12 | ;; | 31 | ;; |
| 13 | ;; Here is a brief explanation how this code works. | 32 | ;; Here is a brief explanation how this code works. |
| 14 | ;; Firstly, we analyse the tree by calling cconv-analyse-form. | 33 | ;; Firstly, we analyse the tree by calling cconv-analyse-form. |
| 15 | ;; This function finds all mutated variables, all functions that are suitable | 34 | ;; This function finds all mutated variables, all functions that are suitable |
| 16 | ;; for lambda lifting and all variables captured by closure. It passes the tree | 35 | ;; for lambda lifting and all variables captured by closure. It passes the tree |
| 17 | ;; once, returning a list of three lists. | 36 | ;; once, returning a list of three lists. |
| 18 | ;; | 37 | ;; |
| 19 | ;; Then we calculate the intersection of first and third lists returned by | 38 | ;; Then we calculate the intersection of first and third lists returned by |
| 20 | ;; cconv-analyse form to find all mutated variables that are captured by | 39 | ;; cconv-analyse form to find all mutated variables that are captured by |
| 21 | ;; closure. | 40 | ;; closure. |
| 22 | 41 | ||
| 23 | ;; Armed with this data, we call cconv-closure-convert-rec, that rewrites the | 42 | ;; Armed with this data, we call cconv-closure-convert-rec, that rewrites the |
| 24 | ;; tree recursivly, lifting lambdas where possible, building closures where it | 43 | ;; tree recursivly, lifting lambdas where possible, building closures where it |
| 25 | ;; is needed and eliminating mutable variables used in closure. | 44 | ;; is needed and eliminating mutable variables used in closure. |
| 26 | ;; | 45 | ;; |
| 27 | ;; We do following replacements : | 46 | ;; We do following replacements : |
| 28 | ;; (lambda (v1 ...) ... fv1 fv2 ...) => (lambda (v1 ... fv1 fv2 ) ... fv1 fv2 .) | 47 | ;; (lambda (v1 ...) ... fv1 fv2 ...) => (lambda (v1 ... fv1 fv2 ) ... fv1 fv2 .) |
| 29 | ;; if the function is suitable for lambda lifting (if all calls are known) | 48 | ;; if the function is suitable for lambda lifting (if all calls are known) |
| 30 | ;; | 49 | ;; |
| 31 | ;; (function (lambda (v1 ...) ... fv ...)) => | 50 | ;; (lambda (v1 ...) ... fv ...) => |
| 32 | ;; (curry (lambda (env v1 ...) ... env ...) env) | 51 | ;; (curry (lambda (env v1 ...) ... env ...) env) |
| 33 | ;; if the function has only 1 free variable | 52 | ;; if the function has only 1 free variable |
| 34 | ;; | 53 | ;; |
| 35 | ;; and finally | 54 | ;; and finally |
| 36 | ;; (function (lambda (v1 ...) ... fv1 fv2 ...)) => | 55 | ;; (lambda (v1 ...) ... fv1 fv2 ...) => |
| 37 | ;; (curry (lambda (env v1 ..) .. (aref env 0) (aref env 1) ..) (vector fv1 fv2)) | 56 | ;; (curry (lambda (env v1 ..) .. (aref env 0) (aref env 1) ..) (vector fv1 fv2)) |
| 38 | ;; if the function has 2 or more free variables | 57 | ;; if the function has 2 or more free variables. |
| 39 | ;; | 58 | ;; |
| 40 | ;; If the function has no free variables, we don't do anything. | 59 | ;; If the function has no free variables, we don't do anything. |
| 41 | ;; | ||
| 42 | ;; If the variable is mutable(updated by setq), and it is used in closure | ||
| 43 | ;; we wrap it's definition with list: (list var) and we also replace | ||
| 44 | ;; var => (car var) wherever this variable is used, and also | ||
| 45 | ;; (setq var value) => (setcar var value) where it is updated. | ||
| 46 | ;; | ||
| 47 | ;; If defun argument is closure mutable, we letbind it and wrap it's | ||
| 48 | ;; definition with list. | ||
| 49 | ;; (defun foo (... mutable-arg ...) ...) => | ||
| 50 | ;; (defun foo (... m-arg ...) (let ((m-arg (list m-arg))) ...)) | ||
| 51 | ;; | 60 | ;; |
| 61 | ;; If a variable is mutated (updated by setq), and it is used in a closure | ||
| 62 | ;; we wrap it's definition with list: (list val) and we also replace | ||
| 63 | ;; var => (car var) wherever this variable is used, and also | ||
| 64 | ;; (setq var value) => (setcar var value) where it is updated. | ||
| 52 | ;; | 65 | ;; |
| 53 | ;; | 66 | ;; If defun argument is closure mutable, we letbind it and wrap it's |
| 54 | ;; | 67 | ;; definition with list. |
| 68 | ;; (defun foo (... mutable-arg ...) ...) => | ||
| 69 | ;; (defun foo (... m-arg ...) (let ((m-arg (list m-arg))) ...)) | ||
| 55 | ;; | 70 | ;; |
| 56 | ;;; Code: | 71 | ;;; Code: |
| 57 | 72 | ||
| 58 | (require 'pcase) | ||
| 59 | (eval-when-compile (require 'cl)) | 73 | (eval-when-compile (require 'cl)) |
| 60 | 74 | ||
| 61 | (defconst cconv-liftwhen 3 | 75 | (defconst cconv-liftwhen 3 |
| 62 | "Try to do lambda lifting if the number of arguments + free variables | 76 | "Try to do lambda lifting if the number of arguments + free variables |
| 63 | is less than this number.") | 77 | is less than this number.") |
| 64 | (defvar cconv-mutated | 78 | (defvar cconv-mutated nil |
| 65 | "List of mutated variables in current form") | 79 | "List of mutated variables in current form") |
| 66 | (defvar cconv-captured | 80 | (defvar cconv-captured nil |
| 67 | "List of closure captured variables in current form") | 81 | "List of closure captured variables in current form") |
| 68 | (defvar cconv-captured+mutated | 82 | (defvar cconv-captured+mutated nil |
| 69 | "An intersection between cconv-mutated and cconv-captured lists.") | 83 | "An intersection between cconv-mutated and cconv-captured lists.") |
| 70 | (defvar cconv-lambda-candidates | 84 | (defvar cconv-lambda-candidates nil |
| 71 | "List of candidates for lambda lifting") | 85 | "List of candidates for lambda lifting") |
| 72 | 86 | ||
| 73 | 87 | ||
| 74 | |||
| 75 | (defun cconv-freevars (form &optional fvrs) | 88 | (defun cconv-freevars (form &optional fvrs) |
| 76 | "Find all free variables of given form. | 89 | "Find all free variables of given form. |
| 77 | Arguments: | 90 | Arguments: |
| @@ -83,101 +96,104 @@ Returns a list of free variables." | |||
| 83 | ;; If a leaf in the tree is a symbol, but it is not a global variable, not a | 96 | ;; If a leaf in the tree is a symbol, but it is not a global variable, not a |
| 84 | ;; keyword, not 'nil or 't we consider this leaf as a variable. | 97 | ;; keyword, not 'nil or 't we consider this leaf as a variable. |
| 85 | ;; Free variables are the variables that are not declared above in this tree. | 98 | ;; Free variables are the variables that are not declared above in this tree. |
| 86 | ;; For example free variables of (lambda (a1 a2 ..) body-forms) are | 99 | ;; For example free variables of (lambda (a1 a2 ..) body-forms) are |
| 87 | ;; free variables of body-forms excluding a1, a2 .. | 100 | ;; free variables of body-forms excluding a1, a2 .. |
| 88 | ;; Free variables of (let ((v1 ..) (v2) ..)) body-forms) are | 101 | ;; Free variables of (let ((v1 ..) (v2) ..)) body-forms) are |
| 89 | ;; free variables of body-forms excluding v1, v2 ... | 102 | ;; free variables of body-forms excluding v1, v2 ... |
| 90 | ;; and so on. | 103 | ;; and so on. |
| 91 | 104 | ||
| 92 | ;; a list of free variables already found(FVRS) is passed in parameter | 105 | ;; A list of free variables already found(FVRS) is passed in parameter |
| 93 | ;; to try to use cons or push where possible, and to minimize the usage | 106 | ;; to try to use cons or push where possible, and to minimize the usage |
| 94 | ;; of append | 107 | ;; of append. |
| 95 | 108 | ||
| 96 | ;; This function can contain duplicates(because we use 'append instead | 109 | ;; This function can return duplicates (because we use 'append instead |
| 97 | ;; of union of two sets - for performance reasons). | 110 | ;; of union of two sets - for performance reasons). |
| 98 | (pcase form | 111 | (pcase form |
| 99 | (`(let ,varsvalues . ,body-forms) ; let special form | 112 | (`(let ,varsvalues . ,body-forms) ; let special form |
| 100 | (let ((fvrs-1 '())) | 113 | (let ((fvrs-1 '())) |
| 101 | (dolist (exp body-forms) | 114 | (dolist (exp body-forms) |
| 102 | (setq fvrs-1 (cconv-freevars exp fvrs-1))) | 115 | (setq fvrs-1 (cconv-freevars exp fvrs-1))) |
| 103 | (dolist (elm varsvalues) | 116 | (dolist (elm varsvalues) |
| 104 | (if (listp elm) | 117 | (setq fvrs-1 (delq (if (consp elm) (car elm) elm) fvrs-1))) |
| 105 | (setq fvrs-1 (delq (car elm) fvrs-1)) | 118 | (setq fvrs (nconc fvrs-1 fvrs)) |
| 106 | (setq fvrs-1 (delq elm fvrs-1)))) | 119 | (dolist (exp varsvalues) |
| 107 | (setq fvrs (append fvrs fvrs-1)) | 120 | (when (consp exp) (setq fvrs (cconv-freevars (cadr exp) fvrs)))) |
| 108 | (dolist (exp varsvalues) | 121 | fvrs)) |
| 109 | (when (listp exp) (setq fvrs (cconv-freevars (cadr exp) fvrs)))) | 122 | |
| 110 | fvrs)) | 123 | (`(let* ,varsvalues . ,body-forms) ; let* special form |
| 111 | 124 | (let ((vrs '()) | |
| 112 | (`(let* ,varsvalues . ,body-forms) ; let* special form | 125 | (fvrs-1 '())) |
| 113 | (let ((vrs '()) | 126 | (dolist (exp varsvalues) |
| 114 | (fvrs-1 '())) | 127 | (if (consp exp) |
| 115 | (dolist (exp varsvalues) | 128 | (progn |
| 116 | (if (listp exp) | 129 | (setq fvrs-1 (cconv-freevars (cadr exp) fvrs-1)) |
| 117 | (progn | 130 | (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1))) |
| 118 | (setq fvrs-1 (cconv-freevars (cadr exp) fvrs-1)) | 131 | (push (car exp) vrs)) |
| 119 | (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1))) | 132 | (progn |
| 120 | (push (car exp) vrs)) | 133 | (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1))) |
| 121 | (progn | 134 | (push exp vrs)))) |
| 122 | (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1))) | 135 | (dolist (exp body-forms) |
| 123 | (push exp vrs)))) | 136 | (setq fvrs-1 (cconv-freevars exp fvrs-1))) |
| 124 | (dolist (exp body-forms) | 137 | (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1))) |
| 125 | (setq fvrs-1 (cconv-freevars exp fvrs-1))) | 138 | (append fvrs fvrs-1))) |
| 126 | (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1))) | 139 | |
| 127 | (append fvrs fvrs-1))) | 140 | (`((lambda . ,_) . ,_) ; first element is lambda expression |
| 128 | 141 | (dolist (exp `((function ,(car form)) . ,(cdr form))) | |
| 129 | (`((lambda . ,_) . ,_) ; first element is lambda expression | 142 | (setq fvrs (cconv-freevars exp fvrs))) fvrs) |
| 130 | (dolist (exp `((function ,(car form)) . ,(cdr form))) | 143 | |
| 131 | (setq fvrs (cconv-freevars exp fvrs))) fvrs) | 144 | (`(cond . ,cond-forms) ; cond special form |
| 132 | 145 | (dolist (exp1 cond-forms) | |
| 133 | (`(cond . ,cond-forms) ; cond special form | 146 | (dolist (exp2 exp1) |
| 134 | (dolist (exp1 cond-forms) | 147 | (setq fvrs (cconv-freevars exp2 fvrs)))) fvrs) |
| 135 | (dolist (exp2 exp1) | 148 | |
| 136 | (setq fvrs (cconv-freevars exp2 fvrs)))) fvrs) | 149 | (`(quote . ,_) fvrs) ; quote form |
| 137 | 150 | ||
| 138 | (`(quote . ,_) fvrs) ; quote form | 151 | (`(function . ((lambda ,vars . ,body-forms))) |
| 139 | 152 | (let ((functionform (cadr form)) (fvrs-1 '())) | |
| 140 | (`(function . ((lambda ,vars . ,body-forms))) | 153 | (dolist (exp body-forms) |
| 141 | (let ((functionform (cadr form)) (fvrs-1 '())) | 154 | (setq fvrs-1 (cconv-freevars exp fvrs-1))) |
| 142 | (dolist (exp body-forms) | 155 | (dolist (elm vars) (setq fvrs-1 (delq elm fvrs-1))) |
| 143 | (setq fvrs-1 (cconv-freevars exp fvrs-1))) | 156 | (append fvrs fvrs-1))) ; function form |
| 144 | (dolist (elm vars) (setq fvrs-1 (delq elm fvrs-1))) | 157 | |
| 145 | (append fvrs fvrs-1))) ; function form | 158 | (`(function . ,_) fvrs) ; same as quote |
| 146 | |||
| 147 | (`(function . ,_) fvrs) ; same as quote | ||
| 148 | ;condition-case | 159 | ;condition-case |
| 149 | (`(condition-case ,var ,protected-form . ,conditions-bodies) | 160 | (`(condition-case ,var ,protected-form . ,conditions-bodies) |
| 150 | (let ((fvrs-1 '())) | 161 | (let ((fvrs-1 '())) |
| 151 | (setq fvrs-1 (cconv-freevars protected-form '())) | 162 | (dolist (exp conditions-bodies) |
| 152 | (dolist (exp conditions-bodies) | 163 | (setq fvrs-1 (cconv-freevars (cadr exp) fvrs-1))) |
| 153 | (setq fvrs-1 (cconv-freevars (cadr exp) fvrs-1))) | 164 | (setq fvrs-1 (delq var fvrs-1)) |
| 154 | (setq fvrs-1 (delq var fvrs-1)) | 165 | (setq fvrs-1 (cconv-freevars protected-form fvrs-1)) |
| 155 | (append fvrs fvrs-1))) | 166 | (append fvrs fvrs-1))) |
| 156 | 167 | ||
| 157 | (`(,(and sym (or `defun `defconst `defvar)) . ,_) | 168 | (`(,(and sym (or `defun `defconst `defvar)) . ,_) |
| 158 | ;; we call cconv-freevars only for functions(lambdas) | 169 | ;; we call cconv-freevars only for functions(lambdas) |
| 159 | ;; defun, defconst, defvar are not allowed to be inside | 170 | ;; defun, defconst, defvar are not allowed to be inside |
| 160 | ;; a function(lambda) | 171 | ;; a function(lambda) |
| 161 | (error "Invalid form: %s inside a function" sym)) | 172 | (error "Invalid form: %s inside a function" sym)) |
| 162 | 173 | ||
| 163 | (`(,_ . ,body-forms) ; first element is a function or whatever | 174 | (`(,_ . ,body-forms) ; first element is a function or whatever |
| 164 | (dolist (exp body-forms) | 175 | (dolist (exp body-forms) |
| 165 | (setq fvrs (cconv-freevars exp fvrs))) fvrs) | 176 | (setq fvrs (cconv-freevars exp fvrs))) fvrs) |
| 166 | 177 | ||
| 167 | (_ (if (or (not (symbolp form)) ; form is not a list | 178 | (_ (if (or (not (symbolp form)) ; form is not a list |
| 168 | (special-variable-p form) | 179 | (special-variable-p form) |
| 169 | (memq form '(nil t)) | 180 | ;; byte-compile-bound-variables normally holds both the |
| 170 | (keywordp form)) | 181 | ;; dynamic and lexical vars, but the bytecomp.el should |
| 171 | fvrs | 182 | ;; only call us at the top-level so there shouldn't be |
| 172 | (cons form fvrs))))) | 183 | ;; any lexical vars in it here. |
| 184 | (memq form byte-compile-bound-variables) | ||
| 185 | (memq form '(nil t)) | ||
| 186 | (keywordp form)) | ||
| 187 | fvrs | ||
| 188 | (cons form fvrs))))) | ||
| 173 | 189 | ||
| 174 | ;;;###autoload | 190 | ;;;###autoload |
| 175 | (defun cconv-closure-convert (form &optional toplevel) | 191 | (defun cconv-closure-convert (form &optional toplevel) |
| 176 | ;; cconv-closure-convert-rec has a lot of parameters that are | 192 | ;; cconv-closure-convert-rec has a lot of parameters that are |
| 177 | ;; whether useless for user, whether they should contain | 193 | ;; whether useless for user, whether they should contain |
| 178 | ;; specific data like a list of closure mutables or the list | 194 | ;; specific data like a list of closure mutables or the list |
| 179 | ;; of lambdas suitable for lifting. | 195 | ;; of lambdas suitable for lifting. |
| 180 | ;; | 196 | ;; |
| 181 | ;; That's why this function exists. | 197 | ;; That's why this function exists. |
| 182 | "Main entry point for non-toplevel forms. | 198 | "Main entry point for non-toplevel forms. |
| 183 | -- FORM is a piece of Elisp code after macroexpansion. | 199 | -- FORM is a piece of Elisp code after macroexpansion. |
| @@ -187,705 +203,705 @@ Returns a form where all lambdas don't have any free variables." | |||
| 187 | (let ((cconv-mutated '()) | 203 | (let ((cconv-mutated '()) |
| 188 | (cconv-lambda-candidates '()) | 204 | (cconv-lambda-candidates '()) |
| 189 | (cconv-captured '()) | 205 | (cconv-captured '()) |
| 190 | (cconv-captured+mutated '())) | 206 | (cconv-captured+mutated '())) |
| 191 | ;; Analyse form - fill these variables with new information | 207 | ;; Analyse form - fill these variables with new information |
| 192 | (cconv-analyse-form form '() nil) | 208 | (cconv-analyse-form form '() nil) |
| 193 | ;; Calculate an intersection of cconv-mutated and cconv-captured | 209 | ;; Calculate an intersection of cconv-mutated and cconv-captured |
| 194 | (dolist (mvr cconv-mutated) | 210 | (dolist (mvr cconv-mutated) |
| 195 | (when (memq mvr cconv-captured) ; | 211 | (when (memq mvr cconv-captured) ; |
| 196 | (push mvr cconv-captured+mutated))) | 212 | (push mvr cconv-captured+mutated))) |
| 197 | (cconv-closure-convert-rec | 213 | (cconv-closure-convert-rec |
| 198 | form ; the tree | 214 | form ; the tree |
| 199 | '() ; | 215 | '() ; |
| 200 | '() ; fvrs initially empty | 216 | '() ; fvrs initially empty |
| 201 | '() ; envs initially empty | 217 | '() ; envs initially empty |
| 202 | '() | 218 | '() |
| 203 | toplevel))) ; true if the tree is a toplevel form | 219 | toplevel))) ; true if the tree is a toplevel form |
| 204 | 220 | ||
| 205 | ;;;###autoload | 221 | ;;;###autoload |
| 206 | (defun cconv-closure-convert-toplevel (form) | 222 | (defun cconv-closure-convert-toplevel (form) |
| 207 | "Entry point for toplevel forms. | 223 | "Entry point for toplevel forms. |
| 208 | -- FORM is a piece of Elisp code after macroexpansion. | 224 | -- FORM is a piece of Elisp code after macroexpansion. |
| 209 | 225 | ||
| 210 | Returns a form where all lambdas don't have any free variables." | 226 | Returns a form where all lambdas don't have any free variables." |
| 211 | ;; we distinguish toplevel forms to treat def(un|var|const) correctly. | 227 | ;; we distinguish toplevel forms to treat def(un|var|const) correctly. |
| 212 | (cconv-closure-convert form t)) | 228 | (cconv-closure-convert form t)) |
| 213 | 229 | ||
| 214 | (defun cconv-closure-convert-rec | 230 | (defun cconv-closure-convert-rec |
| 215 | (form emvrs fvrs envs lmenvs defs-are-legal) | 231 | (form emvrs fvrs envs lmenvs defs-are-legal) |
| 216 | ;; This function actually rewrites the tree. | 232 | ;; This function actually rewrites the tree. |
| 217 | "Eliminates all free variables of all lambdas in given forms. | 233 | "Eliminates all free variables of all lambdas in given forms. |
| 218 | Arguments: | 234 | Arguments: |
| 219 | -- FORM is a piece of Elisp code after macroexpansion. | 235 | -- FORM is a piece of Elisp code after macroexpansion. |
| 220 | -- LMENVS is a list of environments used for lambda-lifting. Initially empty. | 236 | -- LMENVS is a list of environments used for lambda-lifting. Initially empty. |
| 221 | -- EMVRS is a list that contains mutated variables that are visible | 237 | -- EMVRS is a list that contains mutated variables that are visible |
| 222 | within current environment. | 238 | within current environment. |
| 223 | -- ENVS is an environment(list of free variables) of current closure. | 239 | -- ENVS is an environment(list of free variables) of current closure. |
| 224 | Initially empty. | 240 | Initially empty. |
| 225 | -- FVRS is a list of variables to substitute in each context. | 241 | -- FVRS is a list of variables to substitute in each context. |
| 226 | Initially empty. | 242 | Initially empty. |
| 227 | -- DEFS-ARE-LEGAL is a boolean variable, true if def(un|var|const) | 243 | -- DEFS-ARE-LEGAL is a boolean variable, true if def(un|var|const) |
| 228 | can be used in this form(e.g. toplevel form) | 244 | can be used in this form(e.g. toplevel form) |
| 229 | 245 | ||
| 230 | Returns a form where all lambdas don't have any free variables." | 246 | Returns a form where all lambdas don't have any free variables." |
| 231 | ;; What's the difference between fvrs and envs? | 247 | ;; What's the difference between fvrs and envs? |
| 232 | ;; Suppose that we have the code | 248 | ;; Suppose that we have the code |
| 233 | ;; (lambda (..) fvr (let ((fvr 1)) (+ fvr 1))) | 249 | ;; (lambda (..) fvr (let ((fvr 1)) (+ fvr 1))) |
| 234 | ;; only the first occurrence of fvr should be replaced by | 250 | ;; only the first occurrence of fvr should be replaced by |
| 235 | ;; (aref env ...). | 251 | ;; (aref env ...). |
| 236 | ;; So initially envs and fvrs are the same thing, but when we descend to | 252 | ;; So initially envs and fvrs are the same thing, but when we descend to |
| 237 | ;; the 'let, we delete fvr from fvrs. Why we don't delete fvr from envs? | 253 | ;; the 'let, we delete fvr from fvrs. Why we don't delete fvr from envs? |
| 238 | ;; Because in envs the order of variables is important. We use this list | 254 | ;; Because in envs the order of variables is important. We use this list |
| 239 | ;; to find the number of a specific variable in the environment vector, | 255 | ;; to find the number of a specific variable in the environment vector, |
| 240 | ;; so we never touch it(unless we enter to the other closure). | 256 | ;; so we never touch it(unless we enter to the other closure). |
| 241 | ;;(if (listp form) (print (car form)) form) | 257 | ;;(if (listp form) (print (car form)) form) |
| 242 | (pcase form | 258 | (pcase form |
| 243 | (`(,(and letsym (or `let* `let)) ,varsvalues . ,body-forms) | 259 | (`(,(and letsym (or `let* `let)) ,varsvalues . ,body-forms) |
| 244 | 260 | ||
| 245 | ; let and let* special forms | 261 | ; let and let* special forms |
| 246 | (let ((body-forms-new '()) | 262 | (let ((body-forms-new '()) |
| 247 | (varsvalues-new '()) | 263 | (varsvalues-new '()) |
| 248 | ;; next for variables needed for delayed push | 264 | ;; next for variables needed for delayed push |
| 249 | ;; because we should process <value(s)> | 265 | ;; because we should process <value(s)> |
| 250 | ;; before we change any arguments | 266 | ;; before we change any arguments |
| 251 | (lmenvs-new '()) ;needed only in case of let | 267 | (lmenvs-new '()) ;needed only in case of let |
| 252 | (emvrs-new '()) ;needed only in case of let | 268 | (emvrs-new '()) ;needed only in case of let |
| 253 | (emvr-push) ;needed only in case of let* | 269 | (emvr-push) ;needed only in case of let* |
| 254 | (lmenv-push)) ;needed only in case of let* | 270 | (lmenv-push)) ;needed only in case of let* |
| 255 | 271 | ||
| 256 | (dolist (elm varsvalues) ;begin of dolist over varsvalues | 272 | (dolist (elm varsvalues) ;begin of dolist over varsvalues |
| 257 | (let (var value elm-new iscandidate ismutated) | 273 | (let (var value elm-new iscandidate ismutated) |
| 258 | (if (listp elm) ; (let (v1) ...) => (let ((v1 nil)) ...) | 274 | (if (listp elm) ; (let (v1) ...) => (let ((v1 nil)) ...) |
| 259 | (progn | 275 | (progn |
| 260 | (setq var (car elm)) | 276 | (setq var (car elm)) |
| 261 | (setq value (cadr elm))) | 277 | (setq value (cadr elm))) |
| 262 | (setq var elm)) | 278 | (setq var elm)) |
| 263 | 279 | ||
| 264 | ;; Check if var is a candidate for lambda lifting | 280 | ;; Check if var is a candidate for lambda lifting |
| 265 | (let ((lcandid cconv-lambda-candidates)) | 281 | (let ((lcandid cconv-lambda-candidates)) |
| 266 | (while (and lcandid (not iscandidate)) | 282 | (while (and lcandid (not iscandidate)) |
| 267 | (when (and (eq (caar lcandid) var) | 283 | (when (and (eq (caar lcandid) var) |
| 268 | (eq (caddar lcandid) elm) | 284 | (eq (caddar lcandid) elm) |
| 269 | (eq (cadr (cddar lcandid)) form)) | 285 | (eq (cadr (cddar lcandid)) form)) |
| 270 | (setq iscandidate t)) | 286 | (setq iscandidate t)) |
| 271 | (setq lcandid (cdr lcandid)))) | 287 | (setq lcandid (cdr lcandid)))) |
| 272 | 288 | ||
| 273 | ; declared variable is a candidate | 289 | ; declared variable is a candidate |
| 274 | ; for lambda lifting | 290 | ; for lambda lifting |
| 275 | (if iscandidate | 291 | (if iscandidate |
| 276 | (let* ((func (cadr elm)) ; function(lambda) itself | 292 | (let* ((func (cadr elm)) ; function(lambda) itself |
| 277 | ; free variables | 293 | ; free variables |
| 278 | (fv (delete-dups (cconv-freevars func '()))) | 294 | (fv (delete-dups (cconv-freevars func '()))) |
| 279 | (funcvars (append fv (cadadr func))) ;function args | 295 | (funcvars (append fv (cadadr func))) ;function args |
| 280 | (funcbodies (cddadr func)) ; function bodies | 296 | (funcbodies (cddadr func)) ; function bodies |
| 281 | (funcbodies-new '())) | 297 | (funcbodies-new '())) |
| 282 | ; lambda lifting condition | 298 | ; lambda lifting condition |
| 283 | (if (or (not fv) (< cconv-liftwhen (length funcvars))) | 299 | (if (or (not fv) (< cconv-liftwhen (length funcvars))) |
| 284 | ; do not lift | 300 | ; do not lift |
| 285 | (setq | 301 | (setq |
| 286 | elm-new | 302 | elm-new |
| 287 | `(,var | 303 | `(,var |
| 288 | ,(cconv-closure-convert-rec | 304 | ,(cconv-closure-convert-rec |
| 289 | func emvrs fvrs envs lmenvs nil))) | 305 | func emvrs fvrs envs lmenvs nil))) |
| 290 | ; lift | 306 | ; lift |
| 291 | (progn | 307 | (progn |
| 292 | (dolist (elm2 funcbodies) | 308 | (dolist (elm2 funcbodies) |
| 293 | (push ; convert function bodies | 309 | (push ; convert function bodies |
| 294 | (cconv-closure-convert-rec | 310 | (cconv-closure-convert-rec |
| 295 | elm2 emvrs nil envs lmenvs nil) | 311 | elm2 emvrs nil envs lmenvs nil) |
| 296 | funcbodies-new)) | 312 | funcbodies-new)) |
| 297 | (if (eq letsym 'let*) | 313 | (if (eq letsym 'let*) |
| 298 | (setq lmenv-push (cons var fv)) | 314 | (setq lmenv-push (cons var fv)) |
| 299 | (push (cons var fv) lmenvs-new)) | 315 | (push (cons var fv) lmenvs-new)) |
| 300 | ; push lifted function | 316 | ; push lifted function |
| 301 | 317 | ||
| 302 | (setq elm-new | 318 | (setq elm-new |
| 303 | `(,var | 319 | `(,var |
| 304 | (function . | 320 | (function . |
| 305 | ((lambda ,funcvars . | 321 | ((lambda ,funcvars . |
| 306 | ,(reverse funcbodies-new))))))))) | 322 | ,(reverse funcbodies-new))))))))) |
| 307 | 323 | ||
| 308 | ;declared variable is not a function | 324 | ;declared variable is not a function |
| 309 | (progn | 325 | (progn |
| 310 | ;; Check if var is mutated | 326 | ;; Check if var is mutated |
| 311 | (let ((lmutated cconv-captured+mutated)) | 327 | (let ((lmutated cconv-captured+mutated)) |
| 312 | (while (and lmutated (not ismutated)) | 328 | (while (and lmutated (not ismutated)) |
| 313 | (when (and (eq (caar lmutated) var) | 329 | (when (and (eq (caar lmutated) var) |
| 314 | (eq (caddar lmutated) elm) | 330 | (eq (caddar lmutated) elm) |
| 315 | (eq (cadr (cddar lmutated)) form)) | 331 | (eq (cadr (cddar lmutated)) form)) |
| 316 | (setq ismutated t)) | 332 | (setq ismutated t)) |
| 317 | (setq lmutated (cdr lmutated)))) | 333 | (setq lmutated (cdr lmutated)))) |
| 318 | (if ismutated | 334 | (if ismutated |
| 319 | (progn ; declared variable is mutated | 335 | (progn ; declared variable is mutated |
| 320 | (setq elm-new | 336 | (setq elm-new |
| 321 | `(,var (list ,(cconv-closure-convert-rec | 337 | `(,var (list ,(cconv-closure-convert-rec |
| 322 | value emvrs | 338 | value emvrs |
| 323 | fvrs envs lmenvs nil)))) | 339 | fvrs envs lmenvs nil)))) |
| 324 | (if (eq letsym 'let*) | 340 | (if (eq letsym 'let*) |
| 325 | (setq emvr-push var) | 341 | (setq emvr-push var) |
| 326 | (push var emvrs-new))) | 342 | (push var emvrs-new))) |
| 327 | (progn | 343 | (progn |
| 328 | (setq | 344 | (setq |
| 329 | elm-new | 345 | elm-new |
| 330 | `(,var ; else | 346 | `(,var ; else |
| 331 | ,(cconv-closure-convert-rec | 347 | ,(cconv-closure-convert-rec |
| 332 | value emvrs fvrs envs lmenvs nil))))))) | 348 | value emvrs fvrs envs lmenvs nil))))))) |
| 333 | 349 | ||
| 334 | ;; this piece of code below letbinds free | 350 | ;; this piece of code below letbinds free |
| 335 | ;; variables of a lambda lifted function | 351 | ;; variables of a lambda lifted function |
| 336 | ;; if they are redefined in this let | 352 | ;; if they are redefined in this let |
| 337 | ;; example: | 353 | ;; example: |
| 338 | ;; (let* ((fun (lambda (x) (+ x y))) (y 1)) (funcall fun 1)) | 354 | ;; (let* ((fun (lambda (x) (+ x y))) (y 1)) (funcall fun 1)) |
| 339 | ;; Here we can not pass y as parameter because it is | 355 | ;; Here we can not pass y as parameter because it is |
| 340 | ;; redefined. We add a (closed-y y) declaration. | 356 | ;; redefined. We add a (closed-y y) declaration. |
| 341 | ;; We do that even if the function is not used inside | 357 | ;; We do that even if the function is not used inside |
| 342 | ;; this let(*). The reason why we ignore this case is | 358 | ;; this let(*). The reason why we ignore this case is |
| 343 | ;; that we can't "look forward" to see if the function | 359 | ;; that we can't "look forward" to see if the function |
| 344 | ;; is called there or not. To treat well this case we | 360 | ;; is called there or not. To treat well this case we |
| 345 | ;; need to traverse the tree one more time to collect this | 361 | ;; need to traverse the tree one more time to collect this |
| 346 | ;; data, and I think that it's not worth it. | 362 | ;; data, and I think that it's not worth it. |
| 347 | 363 | ||
| 348 | (when (eq letsym 'let*) | 364 | (when (eq letsym 'let*) |
| 349 | (let ((closedsym '()) | 365 | (let ((closedsym '()) |
| 350 | (new-lmenv '()) | 366 | (new-lmenv '()) |
| 351 | (old-lmenv '())) | 367 | (old-lmenv '())) |
| 352 | (dolist (lmenv lmenvs) | 368 | (dolist (lmenv lmenvs) |
| 353 | (when (memq var (cdr lmenv)) | 369 | (when (memq var (cdr lmenv)) |
| 354 | (setq closedsym | 370 | (setq closedsym |
| 355 | (make-symbol | 371 | (make-symbol |
| 356 | (concat "closed-" (symbol-name var)))) | 372 | (concat "closed-" (symbol-name var)))) |
| 357 | (setq new-lmenv (list (car lmenv))) | 373 | (setq new-lmenv (list (car lmenv))) |
| 358 | (dolist (frv (cdr lmenv)) (if (eq frv var) | 374 | (dolist (frv (cdr lmenv)) (if (eq frv var) |
| 359 | (push closedsym new-lmenv) | 375 | (push closedsym new-lmenv) |
| 360 | (push frv new-lmenv))) | 376 | (push frv new-lmenv))) |
| 361 | (setq new-lmenv (reverse new-lmenv)) | 377 | (setq new-lmenv (reverse new-lmenv)) |
| 362 | (setq old-lmenv lmenv))) | 378 | (setq old-lmenv lmenv))) |
| 363 | (when new-lmenv | 379 | (when new-lmenv |
| 364 | (setq lmenvs (remq old-lmenv lmenvs)) | 380 | (setq lmenvs (remq old-lmenv lmenvs)) |
| 365 | (push new-lmenv lmenvs) | 381 | (push new-lmenv lmenvs) |
| 366 | (push `(,closedsym ,var) varsvalues-new)))) | 382 | (push `(,closedsym ,var) varsvalues-new)))) |
| 367 | ;; we push the element after redefined free variables | 383 | ;; we push the element after redefined free variables |
| 368 | ;; are processes. this is important to avoid the bug | 384 | ;; are processes. this is important to avoid the bug |
| 369 | ;; when free variable and the function have the same | 385 | ;; when free variable and the function have the same |
| 370 | ;; name | 386 | ;; name |
| 371 | (push elm-new varsvalues-new) | 387 | (push elm-new varsvalues-new) |
| 372 | 388 | ||
| 373 | (when (eq letsym 'let*) ; update fvrs | 389 | (when (eq letsym 'let*) ; update fvrs |
| 374 | (setq fvrs (remq var fvrs)) | 390 | (setq fvrs (remq var fvrs)) |
| 375 | (setq emvrs (remq var emvrs)) ; remove if redefined | 391 | (setq emvrs (remq var emvrs)) ; remove if redefined |
| 376 | (when emvr-push | 392 | (when emvr-push |
| 377 | (push emvr-push emvrs) | 393 | (push emvr-push emvrs) |
| 378 | (setq emvr-push nil)) | 394 | (setq emvr-push nil)) |
| 379 | (let (lmenvs-1) ; remove var from lmenvs if redefined | 395 | (let (lmenvs-1) ; remove var from lmenvs if redefined |
| 380 | (dolist (iter lmenvs) | 396 | (dolist (iter lmenvs) |
| 381 | (when (not (assq var lmenvs)) | 397 | (when (not (assq var lmenvs)) |
| 382 | (push iter lmenvs-1))) | 398 | (push iter lmenvs-1))) |
| 383 | (setq lmenvs lmenvs-1)) | 399 | (setq lmenvs lmenvs-1)) |
| 384 | (when lmenv-push | 400 | (when lmenv-push |
| 385 | (push lmenv-push lmenvs) | 401 | (push lmenv-push lmenvs) |
| 386 | (setq lmenv-push nil))) | 402 | (setq lmenv-push nil))) |
| 387 | )) ; end of dolist over varsvalues | 403 | )) ; end of dolist over varsvalues |
| 388 | (when (eq letsym 'let) | 404 | (when (eq letsym 'let) |
| 389 | 405 | ||
| 390 | (let (var fvrs-1 emvrs-1 lmenvs-1) | 406 | (let (var fvrs-1 emvrs-1 lmenvs-1) |
| 391 | ;; Here we update emvrs, fvrs and lmenvs lists | 407 | ;; Here we update emvrs, fvrs and lmenvs lists |
| 392 | (dolist (vr fvrs) | 408 | (dolist (vr fvrs) |
| 393 | ; safely remove | 409 | ; safely remove |
| 394 | (when (not (assq vr varsvalues-new)) (push vr fvrs-1))) | 410 | (when (not (assq vr varsvalues-new)) (push vr fvrs-1))) |
| 395 | (setq fvrs fvrs-1) | 411 | (setq fvrs fvrs-1) |
| 396 | (dolist (vr emvrs) | 412 | (dolist (vr emvrs) |
| 397 | ; safely remove | 413 | ; safely remove |
| 398 | (when (not (assq vr varsvalues-new)) (push vr emvrs-1))) | 414 | (when (not (assq vr varsvalues-new)) (push vr emvrs-1))) |
| 399 | (setq emvrs emvrs-1) | 415 | (setq emvrs emvrs-1) |
| 400 | ; push new | 416 | ; push new |
| 401 | (setq emvrs (append emvrs emvrs-new)) | 417 | (setq emvrs (append emvrs emvrs-new)) |
| 402 | (dolist (vr lmenvs) | 418 | (dolist (vr lmenvs) |
| 403 | (when (not (assq (car vr) varsvalues-new)) | 419 | (when (not (assq (car vr) varsvalues-new)) |
| 404 | (push vr lmenvs-1))) | 420 | (push vr lmenvs-1))) |
| 405 | (setq lmenvs (append lmenvs lmenvs-new))) | 421 | (setq lmenvs (append lmenvs lmenvs-new))) |
| 406 | 422 | ||
| 407 | ;; Here we do the same letbinding as for let* above | 423 | ;; Here we do the same letbinding as for let* above |
| 408 | ;; to avoid situation when a free variable of a lambda lifted | 424 | ;; to avoid situation when a free variable of a lambda lifted |
| 409 | ;; function got redefined. | 425 | ;; function got redefined. |
| 410 | 426 | ||
| 411 | (let ((new-lmenv) | 427 | (let ((new-lmenv) |
| 412 | (var nil) | 428 | (var nil) |
| 413 | (closedsym nil) | 429 | (closedsym nil) |
| 414 | (letbinds '()) | 430 | (letbinds '()) |
| 415 | (fvrs-new)) ; list of (closed-var var) | 431 | (fvrs-new)) ; list of (closed-var var) |
| 416 | (dolist (elm varsvalues) | 432 | (dolist (elm varsvalues) |
| 417 | (if (listp elm) | 433 | (if (listp elm) |
| 418 | (setq var (car elm)) | 434 | (setq var (car elm)) |
| 419 | (setq var elm)) | 435 | (setq var elm)) |
| 420 | 436 | ||
| 421 | (let ((lmenvs-1 lmenvs)) ; just to avoid manipulating | 437 | (let ((lmenvs-1 lmenvs)) ; just to avoid manipulating |
| 422 | (dolist (lmenv lmenvs-1) ; the counter inside the loop | 438 | (dolist (lmenv lmenvs-1) ; the counter inside the loop |
| 423 | (when (memq var (cdr lmenv)) | 439 | (when (memq var (cdr lmenv)) |
| 424 | (setq closedsym (make-symbol | 440 | (setq closedsym (make-symbol |
| 425 | (concat "closed-" | 441 | (concat "closed-" |
| 426 | (symbol-name var)))) | 442 | (symbol-name var)))) |
| 427 | 443 | ||
| 428 | (setq new-lmenv (list (car lmenv))) | 444 | (setq new-lmenv (list (car lmenv))) |
| 429 | (dolist (frv (cdr lmenv)) (if (eq frv var) | 445 | (dolist (frv (cdr lmenv)) (if (eq frv var) |
| 430 | (push closedsym new-lmenv) | 446 | (push closedsym new-lmenv) |
| 431 | (push frv new-lmenv))) | 447 | (push frv new-lmenv))) |
| 432 | (setq new-lmenv (reverse new-lmenv)) | 448 | (setq new-lmenv (reverse new-lmenv)) |
| 433 | (setq lmenvs (remq lmenv lmenvs)) | 449 | (setq lmenvs (remq lmenv lmenvs)) |
| 434 | (push new-lmenv lmenvs) | 450 | (push new-lmenv lmenvs) |
| 435 | (push `(,closedsym ,var) letbinds) | 451 | (push `(,closedsym ,var) letbinds) |
| 436 | )))) | 452 | )))) |
| 437 | (setq varsvalues-new (append varsvalues-new letbinds)))) | 453 | (setq varsvalues-new (append varsvalues-new letbinds)))) |
| 438 | 454 | ||
| 439 | (dolist (elm body-forms) ; convert body forms | 455 | (dolist (elm body-forms) ; convert body forms |
| 440 | (push (cconv-closure-convert-rec | 456 | (push (cconv-closure-convert-rec |
| 441 | elm emvrs fvrs envs lmenvs nil) | 457 | elm emvrs fvrs envs lmenvs nil) |
| 442 | body-forms-new)) | 458 | body-forms-new)) |
| 443 | `(,letsym ,(reverse varsvalues-new) . ,(reverse body-forms-new)))) | 459 | `(,letsym ,(reverse varsvalues-new) . ,(reverse body-forms-new)))) |
| 444 | ;end of let let* forms | 460 | ;end of let let* forms |
| 445 | 461 | ||
| 446 | ; first element is lambda expression | 462 | ; first element is lambda expression |
| 447 | (`(,(and `(lambda . ,_) fun) . ,other-body-forms) | 463 | (`(,(and `(lambda . ,_) fun) . ,other-body-forms) |
| 448 | 464 | ||
| 449 | (let ((other-body-forms-new '())) | 465 | (let ((other-body-forms-new '())) |
| 450 | (dolist (elm other-body-forms) | 466 | (dolist (elm other-body-forms) |
| 451 | (push (cconv-closure-convert-rec | 467 | (push (cconv-closure-convert-rec |
| 452 | elm emvrs fvrs envs lmenvs nil) | 468 | elm emvrs fvrs envs lmenvs nil) |
| 453 | other-body-forms-new)) | 469 | other-body-forms-new)) |
| 454 | (cons | 470 | (cons |
| 455 | (cadr | 471 | (cadr |
| 456 | (cconv-closure-convert-rec | 472 | (cconv-closure-convert-rec |
| 457 | (list 'function fun) emvrs fvrs envs lmenvs nil)) | 473 | (list 'function fun) emvrs fvrs envs lmenvs nil)) |
| 458 | (reverse other-body-forms-new)))) | 474 | (reverse other-body-forms-new)))) |
| 459 | 475 | ||
| 460 | (`(cond . ,cond-forms) ; cond special form | 476 | (`(cond . ,cond-forms) ; cond special form |
| 461 | (let ((cond-forms-new '())) | 477 | (let ((cond-forms-new '())) |
| 462 | (dolist (elm cond-forms) | 478 | (dolist (elm cond-forms) |
| 463 | (push (let ((elm-new '())) | 479 | (push (let ((elm-new '())) |
| 464 | (dolist (elm-2 elm) | 480 | (dolist (elm-2 elm) |
| 465 | (push | 481 | (push |
| 466 | (cconv-closure-convert-rec | 482 | (cconv-closure-convert-rec |
| 467 | elm-2 emvrs fvrs envs lmenvs nil) | 483 | elm-2 emvrs fvrs envs lmenvs nil) |
| 468 | elm-new)) | 484 | elm-new)) |
| 469 | (reverse elm-new)) | 485 | (reverse elm-new)) |
| 470 | cond-forms-new)) | 486 | cond-forms-new)) |
| 471 | (cons 'cond | 487 | (cons 'cond |
| 472 | (reverse cond-forms-new)))) | 488 | (reverse cond-forms-new)))) |
| 473 | 489 | ||
| 474 | (`(quote . ,_) form) ; quote form | 490 | (`(quote . ,_) form) ; quote form |
| 475 | 491 | ||
| 476 | (`(function . ((lambda ,vars . ,body-forms))) ; function form | 492 | (`(function . ((lambda ,vars . ,body-forms))) ; function form |
| 477 | (let (fvrs-new) ; we remove vars from fvrs | 493 | (let (fvrs-new) ; we remove vars from fvrs |
| 478 | (dolist (elm fvrs) ;i use such a tricky way to avoid side effects | 494 | (dolist (elm fvrs) ;i use such a tricky way to avoid side effects |
| 479 | (when (not (memq elm vars)) | 495 | (when (not (memq elm vars)) |
| 480 | (push elm fvrs-new))) | 496 | (push elm fvrs-new))) |
| 481 | (setq fvrs fvrs-new)) | 497 | (setq fvrs fvrs-new)) |
| 482 | (let* ((fv (delete-dups (cconv-freevars form '()))) | 498 | (let* ((fv (delete-dups (cconv-freevars form '()))) |
| 483 | (leave fvrs) ; leave = non nil if we should leave env unchanged | 499 | (leave fvrs) ; leave = non nil if we should leave env unchanged |
| 484 | (body-forms-new '()) | 500 | (body-forms-new '()) |
| 485 | (letbind '()) | 501 | (letbind '()) |
| 486 | (mv nil) | 502 | (mv nil) |
| 487 | (envector nil)) | 503 | (envector nil)) |
| 488 | (when fv | 504 | (when fv |
| 489 | ;; Here we form our environment vector. | 505 | ;; Here we form our environment vector. |
| 490 | ;; If outer closure contains all | 506 | ;; If outer closure contains all |
| 491 | ;; free variables of this function(and nothing else) | 507 | ;; free variables of this function(and nothing else) |
| 492 | ;; then we use the same environment vector as for outer closure, | 508 | ;; then we use the same environment vector as for outer closure, |
| 493 | ;; i.e. we leave the environment vector unchanged | 509 | ;; i.e. we leave the environment vector unchanged |
| 494 | ;; otherwise we build a new environmet vector | 510 | ;; otherwise we build a new environmet vector |
| 495 | (if (eq (length envs) (length fv)) | 511 | (if (eq (length envs) (length fv)) |
| 496 | (let ((fv-temp fv)) | 512 | (let ((fv-temp fv)) |
| 497 | (while (and fv-temp leave) | 513 | (while (and fv-temp leave) |
| 498 | (when (not (memq (car fv-temp) fvrs)) (setq leave nil)) | 514 | (when (not (memq (car fv-temp) fvrs)) (setq leave nil)) |
| 499 | (setq fv-temp (cdr fv-temp)))) | 515 | (setq fv-temp (cdr fv-temp)))) |
| 500 | (setq leave nil)) | 516 | (setq leave nil)) |
| 501 | 517 | ||
| 502 | (if (not leave) | 518 | (if (not leave) |
| 503 | (progn | 519 | (progn |
| 504 | (dolist (elm fv) | 520 | (dolist (elm fv) |
| 505 | (push | 521 | (push |
| 506 | (cconv-closure-convert-rec | 522 | (cconv-closure-convert-rec |
| 507 | elm (remq elm emvrs) fvrs envs lmenvs nil) | 523 | elm (remq elm emvrs) fvrs envs lmenvs nil) |
| 508 | envector)) ; process vars for closure vector | 524 | envector)) ; process vars for closure vector |
| 509 | (setq envector (reverse envector)) | 525 | (setq envector (reverse envector)) |
| 510 | (setq envs fv)) | 526 | (setq envs fv)) |
| 511 | (setq envector `(env))) ; leave unchanged | 527 | (setq envector `(env))) ; leave unchanged |
| 512 | (setq fvrs fv)) ; update substitution list | 528 | (setq fvrs fv)) ; update substitution list |
| 513 | 529 | ||
| 514 | ;; the difference between envs and fvrs is explained | 530 | ;; the difference between envs and fvrs is explained |
| 515 | ;; in comment in the beginning of the function | 531 | ;; in comment in the beginning of the function |
| 516 | (dolist (elm cconv-captured+mutated) ; find mutated arguments | 532 | (dolist (elm cconv-captured+mutated) ; find mutated arguments |
| 517 | (setq mv (car elm)) ; used in inner closures | 533 | (setq mv (car elm)) ; used in inner closures |
| 518 | (when (and (memq mv vars) (eq form (caddr elm))) | 534 | (when (and (memq mv vars) (eq form (caddr elm))) |
| 519 | (progn (push mv emvrs) | 535 | (progn (push mv emvrs) |
| 520 | (push `(,mv (list ,mv)) letbind)))) | 536 | (push `(,mv (list ,mv)) letbind)))) |
| 521 | (dolist (elm body-forms) ; convert function body | 537 | (dolist (elm body-forms) ; convert function body |
| 522 | (push (cconv-closure-convert-rec | 538 | (push (cconv-closure-convert-rec |
| 523 | elm emvrs fvrs envs lmenvs nil) | 539 | elm emvrs fvrs envs lmenvs nil) |
| 524 | body-forms-new)) | 540 | body-forms-new)) |
| 525 | 541 | ||
| 526 | (setq body-forms-new | 542 | (setq body-forms-new |
| 527 | (if letbind `((let ,letbind . ,(reverse body-forms-new))) | 543 | (if letbind `((let ,letbind . ,(reverse body-forms-new))) |
| 528 | (reverse body-forms-new))) | 544 | (reverse body-forms-new))) |
| 529 | 545 | ||
| 530 | (cond | 546 | (cond |
| 531 | ;if no freevars - do nothing | 547 | ;if no freevars - do nothing |
| 532 | ((null envector) | 548 | ((null envector) |
| 533 | `(function (lambda ,vars . ,body-forms-new))) | 549 | `(function (lambda ,vars . ,body-forms-new))) |
| 534 | ; 1 free variable - do not build vector | 550 | ; 1 free variable - do not build vector |
| 535 | ((null (cdr envector)) | 551 | ((null (cdr envector)) |
| 536 | `(curry | 552 | `(curry |
| 537 | (function (lambda (env . ,vars) . ,body-forms-new)) | 553 | (function (lambda (env . ,vars) . ,body-forms-new)) |
| 538 | ,(car envector))) | 554 | ,(car envector))) |
| 539 | ; >=2 free variables - build vector | 555 | ; >=2 free variables - build vector |
| 540 | (t | 556 | (t |
| 541 | `(curry | 557 | `(curry |
| 542 | (function (lambda (env . ,vars) . ,body-forms-new)) | 558 | (function (lambda (env . ,vars) . ,body-forms-new)) |
| 543 | (vector . ,envector)))))) | 559 | (vector . ,envector)))))) |
| 544 | 560 | ||
| 545 | (`(function . ,_) form) ; same as quote | 561 | (`(function . ,_) form) ; same as quote |
| 546 | 562 | ||
| 547 | ;defconst, defvar | 563 | ;defconst, defvar |
| 548 | (`(,(and sym (or `defconst `defvar)) ,definedsymbol . ,body-forms) | 564 | (`(,(and sym (or `defconst `defvar)) ,definedsymbol . ,body-forms) |
| 549 | 565 | ||
| 550 | (if defs-are-legal | 566 | (if defs-are-legal |
| 551 | (let ((body-forms-new '())) | 567 | (let ((body-forms-new '())) |
| 552 | (dolist (elm body-forms) | 568 | (dolist (elm body-forms) |
| 553 | (push (cconv-closure-convert-rec | 569 | (push (cconv-closure-convert-rec |
| 554 | elm emvrs fvrs envs lmenvs nil) | 570 | elm emvrs fvrs envs lmenvs nil) |
| 555 | body-forms-new)) | 571 | body-forms-new)) |
| 556 | (setq body-forms-new (reverse body-forms-new)) | 572 | (setq body-forms-new (reverse body-forms-new)) |
| 557 | `(,sym ,definedsymbol . ,body-forms-new)) | 573 | `(,sym ,definedsymbol . ,body-forms-new)) |
| 558 | (error "Invalid form: %s inside a function" sym))) | 574 | (error "Invalid form: %s inside a function" sym))) |
| 559 | 575 | ||
| 560 | ;defun, defmacro, defsubst | 576 | ;defun, defmacro |
| 561 | (`(,(and sym (or `defun `defmacro `defsubst)) | 577 | (`(,(and sym (or `defun `defmacro)) |
| 562 | ,func ,vars . ,body-forms) | 578 | ,func ,vars . ,body-forms) |
| 563 | (if defs-are-legal | 579 | (if defs-are-legal |
| 564 | (let ((body-new '()) ; the whole body | 580 | (let ((body-new '()) ; the whole body |
| 565 | (body-forms-new '()) ; body w\o docstring and interactive | 581 | (body-forms-new '()) ; body w\o docstring and interactive |
| 566 | (letbind '())) | 582 | (letbind '())) |
| 567 | ; find mutable arguments | 583 | ; find mutable arguments |
| 568 | (let ((lmutated cconv-captured+mutated) ismutated) | 584 | (let ((lmutated cconv-captured+mutated) ismutated) |
| 569 | (dolist (elm vars) | 585 | (dolist (elm vars) |
| 570 | (setq ismutated nil) | 586 | (setq ismutated nil) |
| 571 | (while (and lmutated (not ismutated)) | 587 | (while (and lmutated (not ismutated)) |
| 572 | (when (and (eq (caar lmutated) elm) | 588 | (when (and (eq (caar lmutated) elm) |
| 573 | (eq (cadar lmutated) form)) | 589 | (eq (cadar lmutated) form)) |
| 574 | (setq ismutated t)) | 590 | (setq ismutated t)) |
| 575 | (setq lmutated (cdr lmutated))) | 591 | (setq lmutated (cdr lmutated))) |
| 576 | (when ismutated | 592 | (when ismutated |
| 577 | (push elm letbind) | 593 | (push elm letbind) |
| 578 | (push elm emvrs)))) | 594 | (push elm emvrs)))) |
| 579 | ;transform body-forms | 595 | ;transform body-forms |
| 580 | (when (stringp (car body-forms)) ; treat docstring well | 596 | (when (stringp (car body-forms)) ; treat docstring well |
| 581 | (push (car body-forms) body-new) | 597 | (push (car body-forms) body-new) |
| 582 | (setq body-forms (cdr body-forms))) | 598 | (setq body-forms (cdr body-forms))) |
| 583 | (when (and (listp (car body-forms)) ; treat (interactive) well | 599 | (when (and (listp (car body-forms)) ; treat (interactive) well |
| 584 | (eq (caar body-forms) 'interactive)) | 600 | (eq (caar body-forms) 'interactive)) |
| 585 | (push | 601 | (push |
| 586 | (cconv-closure-convert-rec | 602 | (cconv-closure-convert-rec |
| 587 | (car body-forms) | 603 | (car body-forms) |
| 588 | emvrs fvrs envs lmenvs nil) body-new) | 604 | emvrs fvrs envs lmenvs nil) body-new) |
| 589 | (setq body-forms (cdr body-forms))) | 605 | (setq body-forms (cdr body-forms))) |
| 590 | 606 | ||
| 591 | (dolist (elm body-forms) | 607 | (dolist (elm body-forms) |
| 592 | (push (cconv-closure-convert-rec | 608 | (push (cconv-closure-convert-rec |
| 593 | elm emvrs fvrs envs lmenvs nil) | 609 | elm emvrs fvrs envs lmenvs nil) |
| 594 | body-forms-new)) | 610 | body-forms-new)) |
| 595 | (setq body-forms-new (reverse body-forms-new)) | 611 | (setq body-forms-new (reverse body-forms-new)) |
| 596 | 612 | ||
| 597 | (if letbind | 613 | (if letbind |
| 598 | ; letbind mutable arguments | 614 | ; letbind mutable arguments |
| 599 | (let ((varsvalues-new '())) | 615 | (let ((varsvalues-new '())) |
| 600 | (dolist (elm letbind) (push `(,elm (list ,elm)) | 616 | (dolist (elm letbind) (push `(,elm (list ,elm)) |
| 601 | varsvalues-new)) | 617 | varsvalues-new)) |
| 602 | (push `(let ,(reverse varsvalues-new) . | 618 | (push `(let ,(reverse varsvalues-new) . |
| 603 | ,body-forms-new) body-new) | 619 | ,body-forms-new) body-new) |
| 604 | (setq body-new (reverse body-new))) | 620 | (setq body-new (reverse body-new))) |
| 605 | (setq body-new (append (reverse body-new) body-forms-new))) | 621 | (setq body-new (append (reverse body-new) body-forms-new))) |
| 606 | 622 | ||
| 607 | `(,sym ,func ,vars . ,body-new)) | 623 | `(,sym ,func ,vars . ,body-new)) |
| 608 | 624 | ||
| 609 | (error "Invalid form: defun inside a function"))) | 625 | (error "Invalid form: defun inside a function"))) |
| 610 | ;condition-case | 626 | ;condition-case |
| 611 | (`(condition-case ,var ,protected-form . ,conditions-bodies) | 627 | (`(condition-case ,var ,protected-form . ,conditions-bodies) |
| 612 | (let ((conditions-bodies-new '())) | 628 | (let ((conditions-bodies-new '())) |
| 613 | (setq fvrs (remq var fvrs)) | 629 | (setq fvrs (remq var fvrs)) |
| 614 | (dolist (elm conditions-bodies) | 630 | (dolist (elm conditions-bodies) |
| 615 | (push (let ((elm-new '())) | 631 | (push (let ((elm-new '())) |
| 616 | (dolist (elm-2 (cdr elm)) | 632 | (dolist (elm-2 (cdr elm)) |
| 617 | (push | 633 | (push |
| 618 | (cconv-closure-convert-rec | 634 | (cconv-closure-convert-rec |
| 619 | elm-2 emvrs fvrs envs lmenvs nil) | 635 | elm-2 emvrs fvrs envs lmenvs nil) |
| 620 | elm-new)) | 636 | elm-new)) |
| 621 | (cons (car elm) (reverse elm-new))) | 637 | (cons (car elm) (reverse elm-new))) |
| 622 | conditions-bodies-new)) | 638 | conditions-bodies-new)) |
| 623 | `(condition-case | 639 | `(condition-case |
| 624 | ,var | 640 | ,var |
| 625 | ,(cconv-closure-convert-rec | 641 | ,(cconv-closure-convert-rec |
| 626 | protected-form emvrs fvrs envs lmenvs nil) | 642 | protected-form emvrs fvrs envs lmenvs nil) |
| 627 | . ,(reverse conditions-bodies-new)))) | 643 | . ,(reverse conditions-bodies-new)))) |
| 628 | 644 | ||
| 629 | (`(setq . ,forms) ; setq special form | 645 | (`(setq . ,forms) ; setq special form |
| 630 | (let (prognlist sym sym-new value) | 646 | (let (prognlist sym sym-new value) |
| 631 | (while forms | 647 | (while forms |
| 632 | (setq sym (car forms)) | 648 | (setq sym (car forms)) |
| 633 | (setq sym-new (cconv-closure-convert-rec | 649 | (setq sym-new (cconv-closure-convert-rec |
| 634 | sym | 650 | sym |
| 635 | (remq sym emvrs) fvrs envs lmenvs nil)) | 651 | (remq sym emvrs) fvrs envs lmenvs nil)) |
| 636 | (setq value | 652 | (setq value |
| 637 | (cconv-closure-convert-rec | 653 | (cconv-closure-convert-rec |
| 638 | (cadr forms) emvrs fvrs envs lmenvs nil)) | 654 | (cadr forms) emvrs fvrs envs lmenvs nil)) |
| 639 | (if (memq sym emvrs) | 655 | (if (memq sym emvrs) |
| 640 | (push `(setcar ,sym-new ,value) prognlist) | 656 | (push `(setcar ,sym-new ,value) prognlist) |
| 641 | (if (symbolp sym-new) | 657 | (if (symbolp sym-new) |
| 642 | (push `(setq ,sym-new ,value) prognlist) | 658 | (push `(setq ,sym-new ,value) prognlist) |
| 643 | (push `(set ,sym-new ,value) prognlist))) | 659 | (push `(set ,sym-new ,value) prognlist))) |
| 644 | (setq forms (cddr forms))) | 660 | (setq forms (cddr forms))) |
| 645 | (if (cdr prognlist) | 661 | (if (cdr prognlist) |
| 646 | `(progn . ,(reverse prognlist)) | 662 | `(progn . ,(reverse prognlist)) |
| 647 | (car prognlist)))) | 663 | (car prognlist)))) |
| 648 | 664 | ||
| 649 | (`(,(and (or `funcall `apply) callsym) ,fun . ,args) | 665 | (`(,(and (or `funcall `apply) callsym) ,fun . ,args) |
| 650 | ; funcall is not a special form | 666 | ; funcall is not a special form |
| 651 | ; but we treat it separately | 667 | ; but we treat it separately |
| 652 | ; for the needs of lambda lifting | 668 | ; for the needs of lambda lifting |
| 653 | (let ((fv (cdr (assq fun lmenvs)))) | 669 | (let ((fv (cdr (assq fun lmenvs)))) |
| 654 | (if fv | 670 | (if fv |
| 655 | (let ((args-new '()) | 671 | (let ((args-new '()) |
| 656 | (processed-fv '())) | 672 | (processed-fv '())) |
| 657 | ;; All args (free variables and actual arguments) | 673 | ;; All args (free variables and actual arguments) |
| 658 | ;; should be processed, because they can be fvrs | 674 | ;; should be processed, because they can be fvrs |
| 659 | ;; (free variables of another closure) | 675 | ;; (free variables of another closure) |
| 660 | (dolist (fvr fv) | 676 | (dolist (fvr fv) |
| 661 | (push (cconv-closure-convert-rec | 677 | (push (cconv-closure-convert-rec |
| 662 | fvr (remq fvr emvrs) | 678 | fvr (remq fvr emvrs) |
| 663 | fvrs envs lmenvs nil) | 679 | fvrs envs lmenvs nil) |
| 664 | processed-fv)) | 680 | processed-fv)) |
| 665 | (setq processed-fv (reverse processed-fv)) | 681 | (setq processed-fv (reverse processed-fv)) |
| 666 | (dolist (elm args) | 682 | (dolist (elm args) |
| 667 | (push (cconv-closure-convert-rec | 683 | (push (cconv-closure-convert-rec |
| 668 | elm emvrs fvrs envs lmenvs nil) | 684 | elm emvrs fvrs envs lmenvs nil) |
| 669 | args-new)) | 685 | args-new)) |
| 670 | (setq args-new (append processed-fv (reverse args-new))) | 686 | (setq args-new (append processed-fv (reverse args-new))) |
| 671 | (setq fun (cconv-closure-convert-rec | 687 | (setq fun (cconv-closure-convert-rec |
| 672 | fun emvrs fvrs envs lmenvs nil)) | 688 | fun emvrs fvrs envs lmenvs nil)) |
| 673 | `(,callsym ,fun . ,args-new)) | 689 | `(,callsym ,fun . ,args-new)) |
| 674 | (let ((cdr-new '())) | 690 | (let ((cdr-new '())) |
| 675 | (dolist (elm (cdr form)) | 691 | (dolist (elm (cdr form)) |
| 676 | (push (cconv-closure-convert-rec | 692 | (push (cconv-closure-convert-rec |
| 677 | elm emvrs fvrs envs lmenvs nil) | 693 | elm emvrs fvrs envs lmenvs nil) |
| 678 | cdr-new)) | 694 | cdr-new)) |
| 679 | `(,callsym . ,(reverse cdr-new)))))) | 695 | `(,callsym . ,(reverse cdr-new)))))) |
| 680 | 696 | ||
| 681 | (`(,func . ,body-forms) ; first element is function or whatever | 697 | (`(,func . ,body-forms) ; first element is function or whatever |
| 682 | ; function-like forms are: | 698 | ; function-like forms are: |
| 683 | ; or, and, if, progn, prog1, prog2, | 699 | ; or, and, if, progn, prog1, prog2, |
| 684 | ; while, until | 700 | ; while, until |
| 685 | (let ((body-forms-new '())) | 701 | (let ((body-forms-new '())) |
| 686 | (dolist (elm body-forms) | 702 | (dolist (elm body-forms) |
| 687 | (push (cconv-closure-convert-rec | 703 | (push (cconv-closure-convert-rec |
| 688 | elm emvrs fvrs envs lmenvs defs-are-legal) | 704 | elm emvrs fvrs envs lmenvs defs-are-legal) |
| 689 | body-forms-new)) | 705 | body-forms-new)) |
| 690 | (setq body-forms-new (reverse body-forms-new)) | 706 | (setq body-forms-new (reverse body-forms-new)) |
| 691 | `(,func . ,body-forms-new))) | 707 | `(,func . ,body-forms-new))) |
| 692 | 708 | ||
| 693 | (_ | 709 | (_ |
| 694 | (if (memq form fvrs) ;form is a free variable | 710 | (if (memq form fvrs) ;form is a free variable |
| 695 | (let* ((numero (position form envs)) | 711 | (let* ((numero (position form envs)) |
| 696 | (var '())) | 712 | (var '())) |
| 697 | (assert numero) | 713 | (assert numero) |
| 698 | (if (null (cdr envs)) | 714 | (if (null (cdr envs)) |
| 699 | (setq var 'env) | 715 | (setq var 'env) |
| 700 | ;replace form => | 716 | ;replace form => |
| 701 | ;(aref env #) | 717 | ;(aref env #) |
| 702 | (setq var `(aref env ,numero))) | 718 | (setq var `(aref env ,numero))) |
| 703 | (if (memq form emvrs) ; form => (car (aref env #)) if mutable | 719 | (if (memq form emvrs) ; form => (car (aref env #)) if mutable |
| 704 | `(car ,var) | 720 | `(car ,var) |
| 705 | var)) | 721 | var)) |
| 706 | (if (memq form emvrs) ; if form is a mutable variable | 722 | (if (memq form emvrs) ; if form is a mutable variable |
| 707 | `(car ,form) ; replace form => (car form) | 723 | `(car ,form) ; replace form => (car form) |
| 708 | form))))) | 724 | form))))) |
| 709 | 725 | ||
| 710 | (defun cconv-analyse-form (form vars inclosure) | 726 | (defun cconv-analyse-form (form vars inclosure) |
| 711 | 727 | ||
| 712 | "Find mutated variables and variables captured by closure. Analyse | 728 | "Find mutated variables and variables captured by closure. Analyse |
| 713 | lambdas if they are suitable for lambda lifting. | 729 | lambdas if they are suitable for lambda lifting. |
| 714 | -- FORM is a piece of Elisp code after macroexpansion. | 730 | -- FORM is a piece of Elisp code after macroexpansion. |
| 715 | -- MLCVRS is a structure that contains captured and mutated variables. | 731 | -- MLCVRS is a structure that contains captured and mutated variables. |
| 716 | (first MLCVRS) is a list of mutated variables, (second MLCVRS) is a | 732 | (first MLCVRS) is a list of mutated variables, (second MLCVRS) is a |
| 717 | list of candidates for lambda lifting and (third MLCVRS) is a list of | 733 | list of candidates for lambda lifting and (third MLCVRS) is a list of |
| 718 | variables captured by closure. It should be (nil nil nil) initially. | 734 | variables captured by closure. It should be (nil nil nil) initially. |
| 719 | -- VARS is a list of local variables visible in current environment | 735 | -- VARS is a list of local variables visible in current environment |
| 720 | (initially empty). | 736 | (initially empty). |
| 721 | -- INCLOSURE is a boolean variable, true if we are in closure. | 737 | -- INCLOSURE is a boolean variable, true if we are in closure. |
| 722 | Initially false" | 738 | Initially false" |
| 723 | (pcase form | 739 | (pcase form |
| 724 | ; let special form | 740 | ; let special form |
| 725 | (`(,(and (or `let* `let) letsym) ,varsvalues . ,body-forms) | 741 | (`(,(and (or `let* `let) letsym) ,varsvalues . ,body-forms) |
| 726 | 742 | ||
| 727 | (when (eq letsym 'let) | 743 | (when (eq letsym 'let) |
| 728 | (dolist (elm varsvalues) ; analyse values | 744 | (dolist (elm varsvalues) ; analyse values |
| 729 | (when (listp elm) | 745 | (when (listp elm) |
| 730 | (cconv-analyse-form (cadr elm) vars inclosure)))) | 746 | (cconv-analyse-form (cadr elm) vars inclosure)))) |
| 731 | 747 | ||
| 732 | (let ((v nil) | 748 | (let ((v nil) |
| 733 | (var nil) | 749 | (var nil) |
| 734 | (value nil) | 750 | (value nil) |
| 735 | (varstruct nil)) | 751 | (varstruct nil)) |
| 736 | (dolist (elm varsvalues) | 752 | (dolist (elm varsvalues) |
| 737 | (if (listp elm) | 753 | (if (listp elm) |
| 738 | (progn | 754 | (progn |
| 739 | (setq var (car elm)) | 755 | (setq var (car elm)) |
| 740 | (setq value (cadr elm))) | 756 | (setq value (cadr elm))) |
| 741 | (progn | 757 | (progn |
| 742 | (setq var elm) ; treat the form (let (x) ...) well | 758 | (setq var elm) ; treat the form (let (x) ...) well |
| 743 | (setq value nil))) | 759 | (setq value nil))) |
| 744 | 760 | ||
| 745 | (when (eq letsym 'let*) ; analyse value | 761 | (when (eq letsym 'let*) ; analyse value |
| 746 | (cconv-analyse-form value vars inclosure)) | 762 | (cconv-analyse-form value vars inclosure)) |
| 747 | 763 | ||
| 748 | (let (vars-new) ; remove the old var | 764 | (let (vars-new) ; remove the old var |
| 749 | (dolist (vr vars) | 765 | (dolist (vr vars) |
| 750 | (when (not (eq (car vr) var)) | 766 | (when (not (eq (car vr) var)) |
| 751 | (push vr vars-new))) | 767 | (push vr vars-new))) |
| 752 | (setq vars vars-new)) | 768 | (setq vars vars-new)) |
| 753 | 769 | ||
| 754 | (setq varstruct (list var inclosure elm form)) | 770 | (setq varstruct (list var inclosure elm form)) |
| 755 | (push varstruct vars) ; push a new one | 771 | (push varstruct vars) ; push a new one |
| 756 | 772 | ||
| 757 | (when (and (listp value) | 773 | (when (and (listp value) |
| 758 | (eq (car value) 'function) | 774 | (eq (car value) 'function) |
| 759 | (eq (caadr value) 'lambda)) | 775 | (eq (caadr value) 'lambda)) |
| 760 | ; if var is a function | 776 | ; if var is a function |
| 761 | ; push it to lambda list | 777 | ; push it to lambda list |
| 762 | (push varstruct cconv-lambda-candidates)))) | 778 | (push varstruct cconv-lambda-candidates)))) |
| 763 | 779 | ||
| 764 | (dolist (elm body-forms) ; analyse body forms | 780 | (dolist (elm body-forms) ; analyse body forms |
| 765 | (cconv-analyse-form elm vars inclosure)) | 781 | (cconv-analyse-form elm vars inclosure)) |
| 766 | nil) | 782 | nil) |
| 767 | ; defun special form | 783 | ; defun special form |
| 768 | (`(,(or `defun `defmacro) ,func ,vrs . ,body-forms) | 784 | (`(,(or `defun `defmacro) ,func ,vrs . ,body-forms) |
| 769 | (let ((v nil)) | 785 | (let ((v nil)) |
| 770 | (dolist (vr vrs) | 786 | (dolist (vr vrs) |
| 771 | (push (list vr form) vars))) ;push vrs to vars | 787 | (push (list vr form) vars))) ;push vrs to vars |
| 772 | (dolist (elm body-forms) ; analyse body forms | 788 | (dolist (elm body-forms) ; analyse body forms |
| 773 | (cconv-analyse-form elm vars inclosure)) | 789 | (cconv-analyse-form elm vars inclosure)) |
| 774 | nil) | 790 | nil) |
| 775 | 791 | ||
| 776 | (`(function . ((lambda ,vrs . ,body-forms))) | 792 | (`(function . ((lambda ,vrs . ,body-forms))) |
| 777 | (if inclosure ;we are in closure | 793 | (if inclosure ;we are in closure |
| 778 | (setq inclosure (+ inclosure 1)) | 794 | (setq inclosure (+ inclosure 1)) |
| 779 | (setq inclosure 1)) | 795 | (setq inclosure 1)) |
| 780 | (let (vars-new) ; update vars | 796 | (let (vars-new) ; update vars |
| 781 | (dolist (vr vars) ; we do that in such a tricky way | 797 | (dolist (vr vars) ; we do that in such a tricky way |
| 782 | (when (not (memq (car vr) vrs)) ; to avoid side effects | 798 | (when (not (memq (car vr) vrs)) ; to avoid side effects |
| 783 | (push vr vars-new))) | 799 | (push vr vars-new))) |
| 784 | (dolist (vr vrs) | 800 | (dolist (vr vrs) |
| 785 | (push (list vr inclosure form) vars-new)) | 801 | (push (list vr inclosure form) vars-new)) |
| 786 | (setq vars vars-new)) | 802 | (setq vars vars-new)) |
| 787 | 803 | ||
| 788 | (dolist (elm body-forms) | 804 | (dolist (elm body-forms) |
| 789 | (cconv-analyse-form elm vars inclosure)) | 805 | (cconv-analyse-form elm vars inclosure)) |
| 790 | nil) | 806 | nil) |
| 791 | 807 | ||
| 792 | (`(setq . ,forms) ; setq | 808 | (`(setq . ,forms) ; setq |
| 793 | ; if a local variable (member of vars) | 809 | ; if a local variable (member of vars) |
| 794 | ; is modified by setq | 810 | ; is modified by setq |
| 795 | ; then it is a mutated variable | 811 | ; then it is a mutated variable |
| 796 | (while forms | 812 | (while forms |
| 797 | (let ((v (assq (car forms) vars))) ; v = non nil if visible | 813 | (let ((v (assq (car forms) vars))) ; v = non nil if visible |
| 798 | (when v | 814 | (when v |
| 799 | (push v cconv-mutated) | 815 | (push v cconv-mutated) |
| 800 | ;; delete from candidate list for lambda lifting | 816 | ;; delete from candidate list for lambda lifting |
| 801 | (setq cconv-lambda-candidates (delq v cconv-lambda-candidates)) | 817 | (setq cconv-lambda-candidates (delq v cconv-lambda-candidates)) |
| 802 | (when inclosure | 818 | (when inclosure |
| 803 | ;; test if v is declared as argument for lambda | 819 | ;; test if v is declared as argument for lambda |
| 804 | (let* ((thirdv (third v)) | 820 | (let* ((thirdv (third v)) |
| 805 | (isarg (if (listp thirdv) | 821 | (isarg (if (listp thirdv) |
| 806 | (eq (car thirdv) 'function) nil))) | 822 | (eq (car thirdv) 'function) nil))) |
| 807 | (if isarg | 823 | (if isarg |
| 808 | (when (> inclosure (cadr v)) ; when we are in closure | 824 | (when (> inclosure (cadr v)) ; when we are in closure |
| 809 | (push v cconv-captured)) ; push it to captured vars | 825 | (push v cconv-captured)) ; push it to captured vars |
| 810 | ;; FIXME more detailed comments needed | 826 | ;; FIXME more detailed comments needed |
| 811 | (push v cconv-captured)))))) | 827 | (push v cconv-captured)))))) |
| 812 | (cconv-analyse-form (cadr forms) vars inclosure) | 828 | (cconv-analyse-form (cadr forms) vars inclosure) |
| 813 | (setq forms (cddr forms))) | 829 | (setq forms (cddr forms))) |
| 814 | nil) | 830 | nil) |
| 815 | 831 | ||
| 816 | (`((lambda . ,_) . ,_) ; first element is lambda expression | 832 | (`((lambda . ,_) . ,_) ; first element is lambda expression |
| 817 | (dolist (exp `((function ,(car form)) . ,(cdr form))) | 833 | (dolist (exp `((function ,(car form)) . ,(cdr form))) |
| 818 | (cconv-analyse-form exp vars inclosure)) | 834 | (cconv-analyse-form exp vars inclosure)) |
| 819 | nil) | 835 | nil) |
| 820 | 836 | ||
| 821 | (`(cond . ,cond-forms) ; cond special form | 837 | (`(cond . ,cond-forms) ; cond special form |
| 822 | (dolist (exp1 cond-forms) | 838 | (dolist (exp1 cond-forms) |
| 823 | (dolist (exp2 exp1) | 839 | (dolist (exp2 exp1) |
| 824 | (cconv-analyse-form exp2 vars inclosure))) | 840 | (cconv-analyse-form exp2 vars inclosure))) |
| 825 | nil) | 841 | nil) |
| 826 | 842 | ||
| 827 | (`(quote . ,_) nil) ; quote form | 843 | (`(quote . ,_) nil) ; quote form |
| 828 | 844 | ||
| 829 | (`(function . ,_) nil) ; same as quote | 845 | (`(function . ,_) nil) ; same as quote |
| 830 | 846 | ||
| 831 | (`(condition-case ,var ,protected-form . ,conditions-bodies) | 847 | (`(condition-case ,var ,protected-form . ,conditions-bodies) |
| 832 | ;condition-case | 848 | ;condition-case |
| 833 | (cconv-analyse-form protected-form vars inclosure) | 849 | (cconv-analyse-form protected-form vars inclosure) |
| 834 | (dolist (exp conditions-bodies) | 850 | (dolist (exp conditions-bodies) |
| 835 | (cconv-analyse-form (cadr exp) vars inclosure)) | 851 | (cconv-analyse-form (cadr exp) vars inclosure)) |
| 836 | nil) | 852 | nil) |
| 837 | 853 | ||
| 838 | (`(,(or `defconst `defvar `defsubst) ,value) | 854 | (`(,(or `defconst `defvar) ,value) |
| 839 | (cconv-analyse-form value vars inclosure)) | 855 | (cconv-analyse-form value vars inclosure)) |
| 840 | 856 | ||
| 841 | (`(,(or `funcall `apply) ,fun . ,args) | 857 | (`(,(or `funcall `apply) ,fun . ,args) |
| 842 | ;; Here we ignore fun because | 858 | ;; Here we ignore fun because |
| 843 | ;; funcall and apply are the only two | 859 | ;; funcall and apply are the only two |
| 844 | ;; functions where we can pass a candidate | 860 | ;; functions where we can pass a candidate |
| 845 | ;; for lambda lifting as argument. | 861 | ;; for lambda lifting as argument. |
| 846 | ;; So, if we see fun elsewhere, we'll | 862 | ;; So, if we see fun elsewhere, we'll |
| 847 | ;; delete it from lambda candidate list. | 863 | ;; delete it from lambda candidate list. |
| 848 | 864 | ||
| 849 | ;; If this funcall and the definition of fun | 865 | ;; If this funcall and the definition of fun |
| 850 | ;; are in different closures - we delete fun from | 866 | ;; are in different closures - we delete fun from |
| 851 | ;; canidate list, because it is too complicated | 867 | ;; canidate list, because it is too complicated |
| 852 | ;; to manage free variables in this case. | 868 | ;; to manage free variables in this case. |
| 853 | (let ((lv (assq fun cconv-lambda-candidates))) | 869 | (let ((lv (assq fun cconv-lambda-candidates))) |
| 854 | (when lv | 870 | (when lv |
| 855 | (when (not (eq (cadr lv) inclosure)) | 871 | (when (not (eq (cadr lv) inclosure)) |
| 856 | (setq cconv-lambda-candidates | 872 | (setq cconv-lambda-candidates |
| 857 | (delq lv cconv-lambda-candidates))))) | 873 | (delq lv cconv-lambda-candidates))))) |
| 858 | 874 | ||
| 859 | (dolist (elm args) | 875 | (dolist (elm args) |
| 860 | (cconv-analyse-form elm vars inclosure)) | 876 | (cconv-analyse-form elm vars inclosure)) |
| 861 | nil) | 877 | nil) |
| 862 | 878 | ||
| 863 | (`(,_ . ,body-forms) ; first element is a function or whatever | 879 | (`(,_ . ,body-forms) ; first element is a function or whatever |
| 864 | (dolist (exp body-forms) | 880 | (dolist (exp body-forms) |
| 865 | (cconv-analyse-form exp vars inclosure)) | 881 | (cconv-analyse-form exp vars inclosure)) |
| 866 | nil) | 882 | nil) |
| 867 | 883 | ||
| 868 | (_ | 884 | (_ |
| 869 | (when (and (symbolp form) | 885 | (when (and (symbolp form) |
| 870 | (not (memq form '(nil t))) | 886 | (not (memq form '(nil t))) |
| 871 | (not (keywordp form)) | 887 | (not (keywordp form)) |
| 872 | (not (special-variable-p form))) | 888 | (not (special-variable-p form))) |
| 873 | (let ((dv (assq form vars))) ; dv = declared and visible | 889 | (let ((dv (assq form vars))) ; dv = declared and visible |
| 874 | (when dv | 890 | (when dv |
| 875 | (when inclosure | 891 | (when inclosure |
| 876 | ;; test if v is declared as argument of lambda | 892 | ;; test if v is declared as argument of lambda |
| 877 | (let* ((thirddv (third dv)) | 893 | (let* ((thirddv (third dv)) |
| 878 | (isarg (if (listp thirddv) | 894 | (isarg (if (listp thirddv) |
| 879 | (eq (car thirddv) 'function) nil))) | 895 | (eq (car thirddv) 'function) nil))) |
| 880 | (if isarg | 896 | (if isarg |
| 881 | ;; FIXME add detailed comments | 897 | ;; FIXME add detailed comments |
| 882 | (when (> inclosure (cadr dv)) ; capturing condition | 898 | (when (> inclosure (cadr dv)) ; capturing condition |
| 883 | (push dv cconv-captured)) | 899 | (push dv cconv-captured)) |
| 884 | (push dv cconv-captured)))) | 900 | (push dv cconv-captured)))) |
| 885 | ; delete lambda | 901 | ; delete lambda |
| 886 | (setq cconv-lambda-candidates ; if it is found here | 902 | (setq cconv-lambda-candidates ; if it is found here |
| 887 | (delq dv cconv-lambda-candidates))))) | 903 | (delq dv cconv-lambda-candidates))))) |
| 888 | nil))) | 904 | nil))) |
| 889 | 905 | ||
| 890 | (provide 'cconv) | 906 | (provide 'cconv) |
| 891 | ;;; cconv.el ends here | 907 | ;;; cconv.el ends here |