aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2011-02-10 18:37:03 -0500
committerStefan Monnier2011-02-10 18:37:03 -0500
commitd779e73c22ae9fedcf6edc6ec286f19cf2e3d89a (patch)
tree099bd33135c87358e721ad3840cba1ff880ed804
parent94d11cb5773b3b37367ee3c4885a374ff129d475 (diff)
downloademacs-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/ChangeLog13
-rw-r--r--lisp/emacs-lisp/bytecomp.el123
-rw-r--r--lisp/emacs-lisp/cconv.el1528
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 @@
12011-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
12011-02-10 Igor Kuzmin <kuzminig@iro.umontreal.ca> 142011-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
63is less than this number.") 77is 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.
77Arguments: 90Arguments:
@@ -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
210Returns a form where all lambdas don't have any free variables." 226Returns 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.
218Arguments: 234Arguments:
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
222within current environment. 238within 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.
224Initially empty. 240Initially 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.
226Initially empty. 242Initially 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)
228can be used in this form(e.g. toplevel form) 244can be used in this form(e.g. toplevel form)
229 245
230Returns a form where all lambdas don't have any free variables." 246Returns 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
713lambdas if they are suitable for lambda lifting. 729lambdas 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
717list of candidates for lambda lifting and (third MLCVRS) is a list of 733list of candidates for lambda lifting and (third MLCVRS) is a list of
718variables captured by closure. It should be (nil nil nil) initially. 734variables 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.
722Initially false" 738Initially 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