aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Kuzmin2011-02-10 13:53:49 -0500
committerStefan Monnier2011-02-10 13:53:49 -0500
commit94d11cb5773b3b37367ee3c4885a374ff129d475 (patch)
treeb7acbbd87cfce602ad52c23f4434a3b27eac83e1
parent8f1d2ef658f95549eb33fe5265f8f11c5129bece (diff)
downloademacs-94d11cb5773b3b37367ee3c4885a374ff129d475.tar.gz
emacs-94d11cb5773b3b37367ee3c4885a374ff129d475.zip
* lisp/emacs-lisp/cconv.el: New file.
* lisp/emacs-lisp/bytecomp.el: Use cconv. (byte-compile-file-form, byte-compile): Call cconv-closure-convert-toplevel when requested. * lisp/server.el: * lisp/mpc.el: * lisp/emacs-lisp/pcase.el: * lisp/doc-view.el: * lisp/dired.el: Use lexical-binding.
-rw-r--r--lisp/ChangeLog12
-rw-r--r--lisp/dired.el1
-rw-r--r--lisp/doc-view.el41
-rw-r--r--lisp/emacs-lisp/bytecomp.el11
-rw-r--r--lisp/emacs-lisp/cconv.el891
-rw-r--r--lisp/emacs-lisp/pcase.el18
-rw-r--r--lisp/mpc.el33
-rw-r--r--lisp/server.el344
8 files changed, 1121 insertions, 230 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 7e3982a5a70..c137860013b 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,15 @@
12011-02-10 Igor Kuzmin <kuzminig@iro.umontreal.ca>
2
3 * emacs-lisp/cconv.el: New file.
4 * emacs-lisp/bytecomp.el: Use cconv.
5 (byte-compile-file-form, byte-compile):
6 Call cconv-closure-convert-toplevel when requested.
7 * server.el:
8 * mpc.el:
9 * emacs-lisp/pcase.el:
10 * doc-view.el:
11 * dired.el: Use lexical-binding.
12
12010-12-27 Stefan Monnier <monnier@iro.umontreal.ca> 132010-12-27 Stefan Monnier <monnier@iro.umontreal.ca>
2 14
3 * emacs-lisp/bytecomp.el (byte-compile-track-mouse): Don't use #'. 15 * emacs-lisp/bytecomp.el (byte-compile-track-mouse): Don't use #'.
diff --git a/lisp/dired.el b/lisp/dired.el
index 02d855a0d33..f98ad641fe3 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -1,3 +1,4 @@
1;;; -*- lexical-binding: t -*-
1;;; dired.el --- directory-browsing commands 2;;; dired.el --- directory-browsing commands
2 3
3;; Copyright (C) 1985-1986, 1992-1997, 2000-2011 4;; Copyright (C) 1985-1986, 1992-1997, 2000-2011
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index c67205fd52b..4f8c338409b 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -1,3 +1,4 @@
1;;; -*- lexical-binding: t -*-
1;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs 2;;; doc-view.el --- View PDF/PostScript/DVI files in Emacs
2 3
3;; Copyright (C) 2007-2011 Free Software Foundation, Inc. 4;; Copyright (C) 2007-2011 Free Software Foundation, Inc.
@@ -155,7 +156,7 @@
155 156
156(defcustom doc-view-ghostscript-options 157(defcustom doc-view-ghostscript-options
157 '("-dSAFER" ;; Avoid security problems when rendering files from untrusted 158 '("-dSAFER" ;; Avoid security problems when rendering files from untrusted
158 ;; sources. 159 ;; sources.
159 "-dNOPAUSE" "-sDEVICE=png16m" "-dTextAlphaBits=4" 160 "-dNOPAUSE" "-sDEVICE=png16m" "-dTextAlphaBits=4"
160 "-dBATCH" "-dGraphicsAlphaBits=4" "-dQUIET") 161 "-dBATCH" "-dGraphicsAlphaBits=4" "-dQUIET")
161 "A list of options to give to ghostscript." 162 "A list of options to give to ghostscript."
@@ -442,9 +443,7 @@ Can be `dvi', `pdf', or `ps'.")
442 doc-view-current-converter-processes) 443 doc-view-current-converter-processes)
443 ;; The PNG file hasn't been generated yet. 444 ;; The PNG file hasn't been generated yet.
444 (doc-view-pdf->png-1 doc-view-buffer-file-name file page 445 (doc-view-pdf->png-1 doc-view-buffer-file-name file page
445 (lexical-let ((page page) 446 (let ((win (selected-window)))
446 (win (selected-window))
447 (file file))
448 (lambda () 447 (lambda ()
449 (and (eq (current-buffer) (window-buffer win)) 448 (and (eq (current-buffer) (window-buffer win))
450 ;; If we changed page in the mean 449 ;; If we changed page in the mean
@@ -453,7 +452,7 @@ Can be `dvi', `pdf', or `ps'.")
453 ;; Make sure we don't infloop. 452 ;; Make sure we don't infloop.
454 (file-readable-p file) 453 (file-readable-p file)
455 (with-selected-window win 454 (with-selected-window win
456 (doc-view-goto-page page)))))))) 455 (doc-view-goto-page page))))))))
457 (overlay-put (doc-view-current-overlay) 456 (overlay-put (doc-view-current-overlay)
458 'help-echo (doc-view-current-info)))) 457 'help-echo (doc-view-current-info))))
459 458
@@ -713,8 +712,8 @@ Should be invoked when the cached images aren't up-to-date."
713 (if (and doc-view-dvipdf-program 712 (if (and doc-view-dvipdf-program
714 (executable-find doc-view-dvipdf-program)) 713 (executable-find doc-view-dvipdf-program))
715 (doc-view-start-process "dvi->pdf" doc-view-dvipdf-program 714 (doc-view-start-process "dvi->pdf" doc-view-dvipdf-program
716 (list dvi pdf) 715 (list dvi pdf)
717 callback) 716 callback)
718 (doc-view-start-process "dvi->pdf" doc-view-dvipdfm-program 717 (doc-view-start-process "dvi->pdf" doc-view-dvipdfm-program
719 (list "-o" pdf dvi) 718 (list "-o" pdf dvi)
720 callback))) 719 callback)))
@@ -735,7 +734,7 @@ is named like ODF with the extension turned to pdf."
735 (list (format "-r%d" (round doc-view-resolution)) 734 (list (format "-r%d" (round doc-view-resolution))
736 (concat "-sOutputFile=" png) 735 (concat "-sOutputFile=" png)
737 pdf-ps)) 736 pdf-ps))
738 (lexical-let ((resolution doc-view-resolution)) 737 (let ((resolution doc-view-resolution))
739 (lambda () 738 (lambda ()
740 ;; Only create the resolution file when it's all done, so it also 739 ;; Only create the resolution file when it's all done, so it also
741 ;; serves as a witness that the conversion is complete. 740 ;; serves as a witness that the conversion is complete.
@@ -780,7 +779,7 @@ Start by converting PAGES, and then the rest."
780 ;; (almost) consecutive, but since in 99% of the cases, there'll be only 779 ;; (almost) consecutive, but since in 99% of the cases, there'll be only
781 ;; a single page anyway, and of the remaining 1%, few cases will have 780 ;; a single page anyway, and of the remaining 1%, few cases will have
782 ;; consecutive pages, it's not worth the trouble. 781 ;; consecutive pages, it's not worth the trouble.
783 (lexical-let ((pdf pdf) (png png) (rest (cdr pages))) 782 (let ((rest (cdr pages)))
784 (doc-view-pdf->png-1 783 (doc-view-pdf->png-1
785 pdf (format png (car pages)) (car pages) 784 pdf (format png (car pages)) (car pages)
786 (lambda () 785 (lambda ()
@@ -793,8 +792,8 @@ Start by converting PAGES, and then the rest."
793 ;; not sufficient. 792 ;; not sufficient.
794 (dolist (win (get-buffer-window-list (current-buffer) nil 'visible)) 793 (dolist (win (get-buffer-window-list (current-buffer) nil 'visible))
795 (with-selected-window win 794 (with-selected-window win
796 (when (stringp (get-char-property (point-min) 'display)) 795 (when (stringp (get-char-property (point-min) 'display))
797 (doc-view-goto-page (doc-view-current-page))))) 796 (doc-view-goto-page (doc-view-current-page)))))
798 ;; Convert the rest of the pages. 797 ;; Convert the rest of the pages.
799 (doc-view-pdf/ps->png pdf png))))))) 798 (doc-view-pdf/ps->png pdf png)))))))
800 799
@@ -816,10 +815,8 @@ Start by converting PAGES, and then the rest."
816 (ps 815 (ps
817 ;; Doc is a PS, so convert it to PDF (which will be converted to 816 ;; Doc is a PS, so convert it to PDF (which will be converted to
818 ;; TXT thereafter). 817 ;; TXT thereafter).
819 (lexical-let ((pdf (expand-file-name "doc.pdf" 818 (let ((pdf (expand-file-name "doc.pdf"
820 (doc-view-current-cache-dir))) 819 (doc-view-current-cache-dir))))
821 (txt txt)
822 (callback callback))
823 (doc-view-ps->pdf doc-view-buffer-file-name pdf 820 (doc-view-ps->pdf doc-view-buffer-file-name pdf
824 (lambda () (doc-view-pdf->txt pdf txt callback))))) 821 (lambda () (doc-view-pdf->txt pdf txt callback)))))
825 (dvi 822 (dvi
@@ -873,9 +870,7 @@ Those files are saved in the directory given by the function
873 (dvi 870 (dvi
874 ;; DVI files have to be converted to PDF before Ghostscript can process 871 ;; DVI files have to be converted to PDF before Ghostscript can process
875 ;; it. 872 ;; it.
876 (lexical-let 873 (let ((pdf (expand-file-name "doc.pdf" doc-view-current-cache-dir)))
877 ((pdf (expand-file-name "doc.pdf" doc-view-current-cache-dir))
878 (png-file png-file))
879 (doc-view-dvi->pdf doc-view-buffer-file-name pdf 874 (doc-view-dvi->pdf doc-view-buffer-file-name pdf
880 (lambda () (doc-view-pdf/ps->png pdf png-file))))) 875 (lambda () (doc-view-pdf/ps->png pdf png-file)))))
881 (odf 876 (odf
@@ -1026,8 +1021,8 @@ have the page we want to view."
1026 (and (not (member pagefile prev-pages)) 1021 (and (not (member pagefile prev-pages))
1027 (member pagefile doc-view-current-files))) 1022 (member pagefile doc-view-current-files)))
1028 (with-selected-window win 1023 (with-selected-window win
1029 (assert (eq (current-buffer) buffer)) 1024 (assert (eq (current-buffer) buffer))
1030 (doc-view-goto-page page)))))))) 1025 (doc-view-goto-page page))))))))
1031 1026
1032(defun doc-view-buffer-message () 1027(defun doc-view-buffer-message ()
1033 ;; Only show this message initially, not when refreshing the buffer (in which 1028 ;; Only show this message initially, not when refreshing the buffer (in which
@@ -1470,9 +1465,9 @@ See the command `doc-view-mode' for more information on this mode."
1470 (when (not (eq major-mode 'doc-view-mode)) 1465 (when (not (eq major-mode 'doc-view-mode))
1471 (doc-view-toggle-display)) 1466 (doc-view-toggle-display))
1472 (with-selected-window 1467 (with-selected-window
1473 (or (get-buffer-window (current-buffer) 0) 1468 (or (get-buffer-window (current-buffer) 0)
1474 (selected-window)) 1469 (selected-window))
1475 (doc-view-goto-page page))))) 1470 (doc-view-goto-page page)))))
1476 1471
1477 1472
1478(provide 'doc-view) 1473(provide 'doc-view)
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index be3e1ed617c..b258524b45f 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -119,6 +119,7 @@
119 119
120(require 'backquote) 120(require 'backquote)
121(require 'macroexp) 121(require 'macroexp)
122(require 'cconv)
122(eval-when-compile (require 'cl)) 123(eval-when-compile (require 'cl))
123 124
124(or (fboundp 'defsubst) 125(or (fboundp 'defsubst)
@@ -2238,6 +2239,8 @@ list that represents a doc string reference.
2238 (let ((byte-compile-current-form nil) ; close over this for warnings. 2239 (let ((byte-compile-current-form nil) ; close over this for warnings.
2239 bytecomp-handler) 2240 bytecomp-handler)
2240 (setq form (macroexpand-all form byte-compile-macro-environment)) 2241 (setq form (macroexpand-all form byte-compile-macro-environment))
2242 (if lexical-binding
2243 (setq form (cconv-closure-convert-toplevel form)))
2241 (cond ((not (consp form)) 2244 (cond ((not (consp form))
2242 (byte-compile-keep-pending form)) 2245 (byte-compile-keep-pending form))
2243 ((and (symbolp (car form)) 2246 ((and (symbolp (car form))
@@ -2585,9 +2588,11 @@ If FORM is a lambda or a macro, byte-compile it as a function."
2585 (setq fun (cdr fun))) 2588 (setq fun (cdr fun)))
2586 (cond ((eq (car-safe fun) 'lambda) 2589 (cond ((eq (car-safe fun) 'lambda)
2587 ;; expand macros 2590 ;; expand macros
2588 (setq fun 2591 (setq fun
2589 (macroexpand-all fun 2592 (macroexpand-all fun
2590 byte-compile-initial-macro-environment)) 2593 byte-compile-initial-macro-environment))
2594 (if lexical-binding
2595 (setq fun (cconv-closure-convert-toplevel fun)))
2591 ;; get rid of the `function' quote added by the `lambda' macro 2596 ;; get rid of the `function' quote added by the `lambda' macro
2592 (setq fun (cadr fun)) 2597 (setq fun (cadr fun))
2593 (setq fun (if macro 2598 (setq fun (if macro
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
new file mode 100644
index 00000000000..ddcc7882d82
--- /dev/null
+++ b/lisp/emacs-lisp/cconv.el
@@ -0,0 +1,891 @@
1;;; -*- lexical-binding: t -*-
2;;; cconv.el --- Closure conversion for statically scoped Emacs lisp.
3
4;; licence stuff will be added later(I don't know yet what to write here)
5
6;;; Commentary:
7
8;; 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
10;; cconv-closure-convert-toplevel(for toplevel forms).
11;; All macros should be expanded.
12;;
13;; Here is a brief explanation how this code works.
14;; Firstly, we analyse the tree by calling cconv-analyse-form.
15;; 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
17;; once, returning a list of three lists.
18;;
19;; 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
21;; closure.
22
23;; Armed with this data, we call cconv-closure-convert-rec, that rewrites the
24;; tree recursivly, lifting lambdas where possible, building closures where it
25;; is needed and eliminating mutable variables used in closure.
26;;
27;; We do following replacements :
28;; (lambda (v1 ...) ... fv1 fv2 ...) => (lambda (v1 ... fv1 fv2 ) ... fv1 fv2 .)
29;; if the function is suitable for lambda lifting (if all calls are known)
30;;
31;; (function (lambda (v1 ...) ... fv ...)) =>
32;; (curry (lambda (env v1 ...) ... env ...) env)
33;; if the function has only 1 free variable
34;;
35;; and finally
36;; (function (lambda (v1 ...) ... fv1 fv2 ...)) =>
37;; (curry (lambda (env v1 ..) .. (aref env 0) (aref env 1) ..) (vector fv1 fv2))
38;; if the function has 2 or more free variables
39;;
40;; 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;;
52;;
53;;
54;;
55;;
56;;; Code:
57
58(require 'pcase)
59(eval-when-compile (require 'cl))
60
61(defconst cconv-liftwhen 3
62 "Try to do lambda lifting if the number of arguments + free variables
63is less than this number.")
64(defvar cconv-mutated
65 "List of mutated variables in current form")
66(defvar cconv-captured
67 "List of closure captured variables in current form")
68(defvar cconv-captured+mutated
69 "An intersection between cconv-mutated and cconv-captured lists.")
70(defvar cconv-lambda-candidates
71 "List of candidates for lambda lifting")
72
73
74
75(defun cconv-freevars (form &optional fvrs)
76 "Find all free variables of given form.
77Arguments:
78-- FORM is a piece of Elisp code after macroexpansion.
79-- FVRS(optional) is a list of variables already found. Used for recursive tree
80traversal
81
82Returns a list of free variables."
83 ;; 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.
85 ;; 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
87 ;; free variables of body-forms excluding a1, a2 ..
88 ;; Free variables of (let ((v1 ..) (v2) ..)) body-forms) are
89 ;; free variables of body-forms excluding v1, v2 ...
90 ;; and so on.
91
92 ;; 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
94 ;; of append
95
96 ;; This function can contain duplicates(because we use 'append instead
97 ;; of union of two sets - for performance reasons).
98 (pcase form
99 (`(let ,varsvalues . ,body-forms) ; let special form
100 (let ((fvrs-1 '()))
101 (dolist (exp body-forms)
102 (setq fvrs-1 (cconv-freevars exp fvrs-1)))
103 (dolist (elm varsvalues)
104 (if (listp elm)
105 (setq fvrs-1 (delq (car elm) fvrs-1))
106 (setq fvrs-1 (delq elm fvrs-1))))
107 (setq fvrs (append fvrs fvrs-1))
108 (dolist (exp varsvalues)
109 (when (listp exp) (setq fvrs (cconv-freevars (cadr exp) fvrs))))
110 fvrs))
111
112 (`(let* ,varsvalues . ,body-forms) ; let* special form
113 (let ((vrs '())
114 (fvrs-1 '()))
115 (dolist (exp varsvalues)
116 (if (listp exp)
117 (progn
118 (setq fvrs-1 (cconv-freevars (cadr exp) fvrs-1))
119 (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1)))
120 (push (car exp) vrs))
121 (progn
122 (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1)))
123 (push exp vrs))))
124 (dolist (exp body-forms)
125 (setq fvrs-1 (cconv-freevars exp fvrs-1)))
126 (dolist (elm vrs) (setq fvrs-1 (delq elm fvrs-1)))
127 (append fvrs fvrs-1)))
128
129 (`((lambda . ,_) . ,_) ; first element is lambda expression
130 (dolist (exp `((function ,(car form)) . ,(cdr form)))
131 (setq fvrs (cconv-freevars exp fvrs))) fvrs)
132
133 (`(cond . ,cond-forms) ; cond special form
134 (dolist (exp1 cond-forms)
135 (dolist (exp2 exp1)
136 (setq fvrs (cconv-freevars exp2 fvrs)))) fvrs)
137
138 (`(quote . ,_) fvrs) ; quote form
139
140 (`(function . ((lambda ,vars . ,body-forms)))
141 (let ((functionform (cadr form)) (fvrs-1 '()))
142 (dolist (exp body-forms)
143 (setq fvrs-1 (cconv-freevars exp fvrs-1)))
144 (dolist (elm vars) (setq fvrs-1 (delq elm fvrs-1)))
145 (append fvrs fvrs-1))) ; function form
146
147 (`(function . ,_) fvrs) ; same as quote
148 ;condition-case
149 (`(condition-case ,var ,protected-form . ,conditions-bodies)
150 (let ((fvrs-1 '()))
151 (setq fvrs-1 (cconv-freevars protected-form '()))
152 (dolist (exp conditions-bodies)
153 (setq fvrs-1 (cconv-freevars (cadr exp) fvrs-1)))
154 (setq fvrs-1 (delq var fvrs-1))
155 (append fvrs fvrs-1)))
156
157 (`(,(and sym (or `defun `defconst `defvar)) . ,_)
158 ;; we call cconv-freevars only for functions(lambdas)
159 ;; defun, defconst, defvar are not allowed to be inside
160 ;; a function(lambda)
161 (error "Invalid form: %s inside a function" sym))
162
163 (`(,_ . ,body-forms) ; first element is a function or whatever
164 (dolist (exp body-forms)
165 (setq fvrs (cconv-freevars exp fvrs))) fvrs)
166
167 (_ (if (or (not (symbolp form)) ; form is not a list
168 (special-variable-p form)
169 (memq form '(nil t))
170 (keywordp form))
171 fvrs
172 (cons form fvrs)))))
173
174;;;###autoload
175(defun cconv-closure-convert (form &optional toplevel)
176 ;; cconv-closure-convert-rec has a lot of parameters that are
177 ;; whether useless for user, whether they should contain
178 ;; specific data like a list of closure mutables or the list
179 ;; of lambdas suitable for lifting.
180 ;;
181 ;; That's why this function exists.
182 "Main entry point for non-toplevel forms.
183-- FORM is a piece of Elisp code after macroexpansion.
184-- TOPLEVEL(optional) is a boolean variable, true if we are at the root of AST
185
186Returns a form where all lambdas don't have any free variables."
187 (let ((cconv-mutated '())
188 (cconv-lambda-candidates '())
189 (cconv-captured '())
190 (cconv-captured+mutated '()))
191 ;; Analyse form - fill these variables with new information
192 (cconv-analyse-form form '() nil)
193 ;; Calculate an intersection of cconv-mutated and cconv-captured
194 (dolist (mvr cconv-mutated)
195 (when (memq mvr cconv-captured) ;
196 (push mvr cconv-captured+mutated)))
197 (cconv-closure-convert-rec
198 form ; the tree
199 '() ;
200 '() ; fvrs initially empty
201 '() ; envs initially empty
202 '()
203 toplevel))) ; true if the tree is a toplevel form
204
205;;;###autoload
206(defun cconv-closure-convert-toplevel (form)
207 "Entry point for toplevel forms.
208-- FORM is a piece of Elisp code after macroexpansion.
209
210Returns a form where all lambdas don't have any free variables."
211 ;; we distinguish toplevel forms to treat def(un|var|const) correctly.
212 (cconv-closure-convert form t))
213
214(defun cconv-closure-convert-rec
215 (form emvrs fvrs envs lmenvs defs-are-legal)
216 ;; This function actually rewrites the tree.
217 "Eliminates all free variables of all lambdas in given forms.
218Arguments:
219-- FORM is a piece of Elisp code after macroexpansion.
220-- LMENVS is a list of environments used for lambda-lifting. Initially empty.
221-- EMVRS is a list that contains mutated variables that are visible
222within current environment.
223-- ENVS is an environment(list of free variables) of current closure.
224Initially empty.
225-- FVRS is a list of variables to substitute in each context.
226Initially empty.
227-- DEFS-ARE-LEGAL is a boolean variable, true if def(un|var|const)
228can be used in this form(e.g. toplevel form)
229
230Returns a form where all lambdas don't have any free variables."
231 ;; What's the difference between fvrs and envs?
232 ;; Suppose that we have the code
233 ;; (lambda (..) fvr (let ((fvr 1)) (+ fvr 1)))
234 ;; only the first occurrence of fvr should be replaced by
235 ;; (aref env ...).
236 ;; 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?
238 ;; 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,
240 ;; so we never touch it(unless we enter to the other closure).
241;;(if (listp form) (print (car form)) form)
242 (pcase form
243 (`(,(and letsym (or `let* `let)) ,varsvalues . ,body-forms)
244
245 ; let and let* special forms
246 (let ((body-forms-new '())
247 (varsvalues-new '())
248 ;; next for variables needed for delayed push
249 ;; because we should process <value(s)>
250 ;; before we change any arguments
251 (lmenvs-new '()) ;needed only in case of let
252 (emvrs-new '()) ;needed only in case of let
253 (emvr-push) ;needed only in case of let*
254 (lmenv-push)) ;needed only in case of let*
255
256 (dolist (elm varsvalues) ;begin of dolist over varsvalues
257 (let (var value elm-new iscandidate ismutated)
258 (if (listp elm) ; (let (v1) ...) => (let ((v1 nil)) ...)
259 (progn
260 (setq var (car elm))
261 (setq value (cadr elm)))
262 (setq var elm))
263
264 ;; Check if var is a candidate for lambda lifting
265 (let ((lcandid cconv-lambda-candidates))
266 (while (and lcandid (not iscandidate))
267 (when (and (eq (caar lcandid) var)
268 (eq (caddar lcandid) elm)
269 (eq (cadr (cddar lcandid)) form))
270 (setq iscandidate t))
271 (setq lcandid (cdr lcandid))))
272
273 ; declared variable is a candidate
274 ; for lambda lifting
275 (if iscandidate
276 (let* ((func (cadr elm)) ; function(lambda) itself
277 ; free variables
278 (fv (delete-dups (cconv-freevars func '())))
279 (funcvars (append fv (cadadr func))) ;function args
280 (funcbodies (cddadr func)) ; function bodies
281 (funcbodies-new '()))
282 ; lambda lifting condition
283 (if (or (not fv) (< cconv-liftwhen (length funcvars)))
284 ; do not lift
285 (setq
286 elm-new
287 `(,var
288 ,(cconv-closure-convert-rec
289 func emvrs fvrs envs lmenvs nil)))
290 ; lift
291 (progn
292 (dolist (elm2 funcbodies)
293 (push ; convert function bodies
294 (cconv-closure-convert-rec
295 elm2 emvrs nil envs lmenvs nil)
296 funcbodies-new))
297 (if (eq letsym 'let*)
298 (setq lmenv-push (cons var fv))
299 (push (cons var fv) lmenvs-new))
300 ; push lifted function
301
302 (setq elm-new
303 `(,var
304 (function .
305 ((lambda ,funcvars .
306 ,(reverse funcbodies-new)))))))))
307
308 ;declared variable is not a function
309 (progn
310 ;; Check if var is mutated
311 (let ((lmutated cconv-captured+mutated))
312 (while (and lmutated (not ismutated))
313 (when (and (eq (caar lmutated) var)
314 (eq (caddar lmutated) elm)
315 (eq (cadr (cddar lmutated)) form))
316 (setq ismutated t))
317 (setq lmutated (cdr lmutated))))
318 (if ismutated
319 (progn ; declared variable is mutated
320 (setq elm-new
321 `(,var (list ,(cconv-closure-convert-rec
322 value emvrs
323 fvrs envs lmenvs nil))))
324 (if (eq letsym 'let*)
325 (setq emvr-push var)
326 (push var emvrs-new)))
327 (progn
328 (setq
329 elm-new
330 `(,var ; else
331 ,(cconv-closure-convert-rec
332 value emvrs fvrs envs lmenvs nil)))))))
333
334 ;; this piece of code below letbinds free
335 ;; variables of a lambda lifted function
336 ;; if they are redefined in this let
337 ;; example:
338 ;; (let* ((fun (lambda (x) (+ x y))) (y 1)) (funcall fun 1))
339 ;; Here we can not pass y as parameter because it is
340 ;; redefined. We add a (closed-y y) declaration.
341 ;; We do that even if the function is not used inside
342 ;; this let(*). The reason why we ignore this case is
343 ;; that we can't "look forward" to see if the function
344 ;; is called there or not. To treat well this case we
345 ;; need to traverse the tree one more time to collect this
346 ;; data, and I think that it's not worth it.
347
348 (when (eq letsym 'let*)
349 (let ((closedsym '())
350 (new-lmenv '())
351 (old-lmenv '()))
352 (dolist (lmenv lmenvs)
353 (when (memq var (cdr lmenv))
354 (setq closedsym
355 (make-symbol
356 (concat "closed-" (symbol-name var))))
357 (setq new-lmenv (list (car lmenv)))
358 (dolist (frv (cdr lmenv)) (if (eq frv var)
359 (push closedsym new-lmenv)
360 (push frv new-lmenv)))
361 (setq new-lmenv (reverse new-lmenv))
362 (setq old-lmenv lmenv)))
363 (when new-lmenv
364 (setq lmenvs (remq old-lmenv lmenvs))
365 (push new-lmenv lmenvs)
366 (push `(,closedsym ,var) varsvalues-new))))
367 ;; we push the element after redefined free variables
368 ;; are processes. this is important to avoid the bug
369 ;; when free variable and the function have the same
370 ;; name
371 (push elm-new varsvalues-new)
372
373 (when (eq letsym 'let*) ; update fvrs
374 (setq fvrs (remq var fvrs))
375 (setq emvrs (remq var emvrs)) ; remove if redefined
376 (when emvr-push
377 (push emvr-push emvrs)
378 (setq emvr-push nil))
379 (let (lmenvs-1) ; remove var from lmenvs if redefined
380 (dolist (iter lmenvs)
381 (when (not (assq var lmenvs))
382 (push iter lmenvs-1)))
383 (setq lmenvs lmenvs-1))
384 (when lmenv-push
385 (push lmenv-push lmenvs)
386 (setq lmenv-push nil)))
387 )) ; end of dolist over varsvalues
388 (when (eq letsym 'let)
389
390 (let (var fvrs-1 emvrs-1 lmenvs-1)
391 ;; Here we update emvrs, fvrs and lmenvs lists
392 (dolist (vr fvrs)
393 ; safely remove
394 (when (not (assq vr varsvalues-new)) (push vr fvrs-1)))
395 (setq fvrs fvrs-1)
396 (dolist (vr emvrs)
397 ; safely remove
398 (when (not (assq vr varsvalues-new)) (push vr emvrs-1)))
399 (setq emvrs emvrs-1)
400 ; push new
401 (setq emvrs (append emvrs emvrs-new))
402 (dolist (vr lmenvs)
403 (when (not (assq (car vr) varsvalues-new))
404 (push vr lmenvs-1)))
405 (setq lmenvs (append lmenvs lmenvs-new)))
406
407 ;; Here we do the same letbinding as for let* above
408 ;; to avoid situation when a free variable of a lambda lifted
409 ;; function got redefined.
410
411 (let ((new-lmenv)
412 (var nil)
413 (closedsym nil)
414 (letbinds '())
415 (fvrs-new)) ; list of (closed-var var)
416 (dolist (elm varsvalues)
417 (if (listp elm)
418 (setq var (car elm))
419 (setq var elm))
420
421 (let ((lmenvs-1 lmenvs)) ; just to avoid manipulating
422 (dolist (lmenv lmenvs-1) ; the counter inside the loop
423 (when (memq var (cdr lmenv))
424 (setq closedsym (make-symbol
425 (concat "closed-"
426 (symbol-name var))))
427
428 (setq new-lmenv (list (car lmenv)))
429 (dolist (frv (cdr lmenv)) (if (eq frv var)
430 (push closedsym new-lmenv)
431 (push frv new-lmenv)))
432 (setq new-lmenv (reverse new-lmenv))
433 (setq lmenvs (remq lmenv lmenvs))
434 (push new-lmenv lmenvs)
435 (push `(,closedsym ,var) letbinds)
436 ))))
437 (setq varsvalues-new (append varsvalues-new letbinds))))
438
439 (dolist (elm body-forms) ; convert body forms
440 (push (cconv-closure-convert-rec
441 elm emvrs fvrs envs lmenvs nil)
442 body-forms-new))
443 `(,letsym ,(reverse varsvalues-new) . ,(reverse body-forms-new))))
444 ;end of let let* forms
445
446 ; first element is lambda expression
447 (`(,(and `(lambda . ,_) fun) . ,other-body-forms)
448
449 (let ((other-body-forms-new '()))
450 (dolist (elm other-body-forms)
451 (push (cconv-closure-convert-rec
452 elm emvrs fvrs envs lmenvs nil)
453 other-body-forms-new))
454 (cons
455 (cadr
456 (cconv-closure-convert-rec
457 (list 'function fun) emvrs fvrs envs lmenvs nil))
458 (reverse other-body-forms-new))))
459
460 (`(cond . ,cond-forms) ; cond special form
461 (let ((cond-forms-new '()))
462 (dolist (elm cond-forms)
463 (push (let ((elm-new '()))
464 (dolist (elm-2 elm)
465 (push
466 (cconv-closure-convert-rec
467 elm-2 emvrs fvrs envs lmenvs nil)
468 elm-new))
469 (reverse elm-new))
470 cond-forms-new))
471 (cons 'cond
472 (reverse cond-forms-new))))
473
474 (`(quote . ,_) form) ; quote form
475
476 (`(function . ((lambda ,vars . ,body-forms))) ; function form
477 (let (fvrs-new) ; we remove vars from fvrs
478 (dolist (elm fvrs) ;i use such a tricky way to avoid side effects
479 (when (not (memq elm vars))
480 (push elm fvrs-new)))
481 (setq fvrs fvrs-new))
482 (let* ((fv (delete-dups (cconv-freevars form '())))
483 (leave fvrs) ; leave = non nil if we should leave env unchanged
484 (body-forms-new '())
485 (letbind '())
486 (mv nil)
487 (envector nil))
488 (when fv
489 ;; Here we form our environment vector.
490 ;; If outer closure contains all
491 ;; free variables of this function(and nothing else)
492 ;; then we use the same environment vector as for outer closure,
493 ;; i.e. we leave the environment vector unchanged
494 ;; otherwise we build a new environmet vector
495 (if (eq (length envs) (length fv))
496 (let ((fv-temp fv))
497 (while (and fv-temp leave)
498 (when (not (memq (car fv-temp) fvrs)) (setq leave nil))
499 (setq fv-temp (cdr fv-temp))))
500 (setq leave nil))
501
502 (if (not leave)
503 (progn
504 (dolist (elm fv)
505 (push
506 (cconv-closure-convert-rec
507 elm (remq elm emvrs) fvrs envs lmenvs nil)
508 envector)) ; process vars for closure vector
509 (setq envector (reverse envector))
510 (setq envs fv))
511 (setq envector `(env))) ; leave unchanged
512 (setq fvrs fv)) ; update substitution list
513
514 ;; the difference between envs and fvrs is explained
515 ;; in comment in the beginning of the function
516 (dolist (elm cconv-captured+mutated) ; find mutated arguments
517 (setq mv (car elm)) ; used in inner closures
518 (when (and (memq mv vars) (eq form (caddr elm)))
519 (progn (push mv emvrs)
520 (push `(,mv (list ,mv)) letbind))))
521 (dolist (elm body-forms) ; convert function body
522 (push (cconv-closure-convert-rec
523 elm emvrs fvrs envs lmenvs nil)
524 body-forms-new))
525
526 (setq body-forms-new
527 (if letbind `((let ,letbind . ,(reverse body-forms-new)))
528 (reverse body-forms-new)))
529
530 (cond
531 ;if no freevars - do nothing
532 ((null envector)
533 `(function (lambda ,vars . ,body-forms-new)))
534 ; 1 free variable - do not build vector
535 ((null (cdr envector))
536 `(curry
537 (function (lambda (env . ,vars) . ,body-forms-new))
538 ,(car envector)))
539 ; >=2 free variables - build vector
540 (t
541 `(curry
542 (function (lambda (env . ,vars) . ,body-forms-new))
543 (vector . ,envector))))))
544
545 (`(function . ,_) form) ; same as quote
546
547 ;defconst, defvar
548 (`(,(and sym (or `defconst `defvar)) ,definedsymbol . ,body-forms)
549
550 (if defs-are-legal
551 (let ((body-forms-new '()))
552 (dolist (elm body-forms)
553 (push (cconv-closure-convert-rec
554 elm emvrs fvrs envs lmenvs nil)
555 body-forms-new))
556 (setq body-forms-new (reverse body-forms-new))
557 `(,sym ,definedsymbol . ,body-forms-new))
558 (error "Invalid form: %s inside a function" sym)))
559
560 ;defun, defmacro, defsubst
561 (`(,(and sym (or `defun `defmacro `defsubst))
562 ,func ,vars . ,body-forms)
563 (if defs-are-legal
564 (let ((body-new '()) ; the whole body
565 (body-forms-new '()) ; body w\o docstring and interactive
566 (letbind '()))
567 ; find mutable arguments
568 (let ((lmutated cconv-captured+mutated) ismutated)
569 (dolist (elm vars)
570 (setq ismutated nil)
571 (while (and lmutated (not ismutated))
572 (when (and (eq (caar lmutated) elm)
573 (eq (cadar lmutated) form))
574 (setq ismutated t))
575 (setq lmutated (cdr lmutated)))
576 (when ismutated
577 (push elm letbind)
578 (push elm emvrs))))
579 ;transform body-forms
580 (when (stringp (car body-forms)) ; treat docstring well
581 (push (car body-forms) body-new)
582 (setq body-forms (cdr body-forms)))
583 (when (and (listp (car body-forms)) ; treat (interactive) well
584 (eq (caar body-forms) 'interactive))
585 (push
586 (cconv-closure-convert-rec
587 (car body-forms)
588 emvrs fvrs envs lmenvs nil) body-new)
589 (setq body-forms (cdr body-forms)))
590
591 (dolist (elm body-forms)
592 (push (cconv-closure-convert-rec
593 elm emvrs fvrs envs lmenvs nil)
594 body-forms-new))
595 (setq body-forms-new (reverse body-forms-new))
596
597 (if letbind
598 ; letbind mutable arguments
599 (let ((varsvalues-new '()))
600 (dolist (elm letbind) (push `(,elm (list ,elm))
601 varsvalues-new))
602 (push `(let ,(reverse varsvalues-new) .
603 ,body-forms-new) body-new)
604 (setq body-new (reverse body-new)))
605 (setq body-new (append (reverse body-new) body-forms-new)))
606
607 `(,sym ,func ,vars . ,body-new))
608
609 (error "Invalid form: defun inside a function")))
610 ;condition-case
611 (`(condition-case ,var ,protected-form . ,conditions-bodies)
612 (let ((conditions-bodies-new '()))
613 (setq fvrs (remq var fvrs))
614 (dolist (elm conditions-bodies)
615 (push (let ((elm-new '()))
616 (dolist (elm-2 (cdr elm))
617 (push
618 (cconv-closure-convert-rec
619 elm-2 emvrs fvrs envs lmenvs nil)
620 elm-new))
621 (cons (car elm) (reverse elm-new)))
622 conditions-bodies-new))
623 `(condition-case
624 ,var
625 ,(cconv-closure-convert-rec
626 protected-form emvrs fvrs envs lmenvs nil)
627 . ,(reverse conditions-bodies-new))))
628
629 (`(setq . ,forms) ; setq special form
630 (let (prognlist sym sym-new value)
631 (while forms
632 (setq sym (car forms))
633 (setq sym-new (cconv-closure-convert-rec
634 sym
635 (remq sym emvrs) fvrs envs lmenvs nil))
636 (setq value
637 (cconv-closure-convert-rec
638 (cadr forms) emvrs fvrs envs lmenvs nil))
639 (if (memq sym emvrs)
640 (push `(setcar ,sym-new ,value) prognlist)
641 (if (symbolp sym-new)
642 (push `(setq ,sym-new ,value) prognlist)
643 (push `(set ,sym-new ,value) prognlist)))
644 (setq forms (cddr forms)))
645 (if (cdr prognlist)
646 `(progn . ,(reverse prognlist))
647 (car prognlist))))
648
649 (`(,(and (or `funcall `apply) callsym) ,fun . ,args)
650 ; funcall is not a special form
651 ; but we treat it separately
652 ; for the needs of lambda lifting
653 (let ((fv (cdr (assq fun lmenvs))))
654 (if fv
655 (let ((args-new '())
656 (processed-fv '()))
657 ;; All args (free variables and actual arguments)
658 ;; should be processed, because they can be fvrs
659 ;; (free variables of another closure)
660 (dolist (fvr fv)
661 (push (cconv-closure-convert-rec
662 fvr (remq fvr emvrs)
663 fvrs envs lmenvs nil)
664 processed-fv))
665 (setq processed-fv (reverse processed-fv))
666 (dolist (elm args)
667 (push (cconv-closure-convert-rec
668 elm emvrs fvrs envs lmenvs nil)
669 args-new))
670 (setq args-new (append processed-fv (reverse args-new)))
671 (setq fun (cconv-closure-convert-rec
672 fun emvrs fvrs envs lmenvs nil))
673 `(,callsym ,fun . ,args-new))
674 (let ((cdr-new '()))
675 (dolist (elm (cdr form))
676 (push (cconv-closure-convert-rec
677 elm emvrs fvrs envs lmenvs nil)
678 cdr-new))
679 `(,callsym . ,(reverse cdr-new))))))
680
681 (`(,func . ,body-forms) ; first element is function or whatever
682 ; function-like forms are:
683 ; or, and, if, progn, prog1, prog2,
684 ; while, until
685 (let ((body-forms-new '()))
686 (dolist (elm body-forms)
687 (push (cconv-closure-convert-rec
688 elm emvrs fvrs envs lmenvs defs-are-legal)
689 body-forms-new))
690 (setq body-forms-new (reverse body-forms-new))
691 `(,func . ,body-forms-new)))
692
693 (_
694 (if (memq form fvrs) ;form is a free variable
695 (let* ((numero (position form envs))
696 (var '()))
697 (assert numero)
698 (if (null (cdr envs))
699 (setq var 'env)
700 ;replace form =>
701 ;(aref env #)
702 (setq var `(aref env ,numero)))
703 (if (memq form emvrs) ; form => (car (aref env #)) if mutable
704 `(car ,var)
705 var))
706 (if (memq form emvrs) ; if form is a mutable variable
707 `(car ,form) ; replace form => (car form)
708 form)))))
709
710(defun cconv-analyse-form (form vars inclosure)
711
712 "Find mutated variables and variables captured by closure. Analyse
713lambdas if they are suitable for lambda lifting.
714-- FORM is a piece of Elisp code after macroexpansion.
715-- MLCVRS is a structure that contains captured and mutated variables.
716 (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
718variables captured by closure. It should be (nil nil nil) initially.
719-- VARS is a list of local variables visible in current environment
720 (initially empty).
721-- INCLOSURE is a boolean variable, true if we are in closure.
722Initially false"
723 (pcase form
724 ; let special form
725 (`(,(and (or `let* `let) letsym) ,varsvalues . ,body-forms)
726
727 (when (eq letsym 'let)
728 (dolist (elm varsvalues) ; analyse values
729 (when (listp elm)
730 (cconv-analyse-form (cadr elm) vars inclosure))))
731
732 (let ((v nil)
733 (var nil)
734 (value nil)
735 (varstruct nil))
736 (dolist (elm varsvalues)
737 (if (listp elm)
738 (progn
739 (setq var (car elm))
740 (setq value (cadr elm)))
741 (progn
742 (setq var elm) ; treat the form (let (x) ...) well
743 (setq value nil)))
744
745 (when (eq letsym 'let*) ; analyse value
746 (cconv-analyse-form value vars inclosure))
747
748 (let (vars-new) ; remove the old var
749 (dolist (vr vars)
750 (when (not (eq (car vr) var))
751 (push vr vars-new)))
752 (setq vars vars-new))
753
754 (setq varstruct (list var inclosure elm form))
755 (push varstruct vars) ; push a new one
756
757 (when (and (listp value)
758 (eq (car value) 'function)
759 (eq (caadr value) 'lambda))
760 ; if var is a function
761 ; push it to lambda list
762 (push varstruct cconv-lambda-candidates))))
763
764 (dolist (elm body-forms) ; analyse body forms
765 (cconv-analyse-form elm vars inclosure))
766 nil)
767 ; defun special form
768 (`(,(or `defun `defmacro) ,func ,vrs . ,body-forms)
769 (let ((v nil))
770 (dolist (vr vrs)
771 (push (list vr form) vars))) ;push vrs to vars
772 (dolist (elm body-forms) ; analyse body forms
773 (cconv-analyse-form elm vars inclosure))
774 nil)
775
776 (`(function . ((lambda ,vrs . ,body-forms)))
777 (if inclosure ;we are in closure
778 (setq inclosure (+ inclosure 1))
779 (setq inclosure 1))
780 (let (vars-new) ; update vars
781 (dolist (vr vars) ; we do that in such a tricky way
782 (when (not (memq (car vr) vrs)) ; to avoid side effects
783 (push vr vars-new)))
784 (dolist (vr vrs)
785 (push (list vr inclosure form) vars-new))
786 (setq vars vars-new))
787
788 (dolist (elm body-forms)
789 (cconv-analyse-form elm vars inclosure))
790 nil)
791
792 (`(setq . ,forms) ; setq
793 ; if a local variable (member of vars)
794 ; is modified by setq
795 ; then it is a mutated variable
796 (while forms
797 (let ((v (assq (car forms) vars))) ; v = non nil if visible
798 (when v
799 (push v cconv-mutated)
800 ;; delete from candidate list for lambda lifting
801 (setq cconv-lambda-candidates (delq v cconv-lambda-candidates))
802 (when inclosure
803 ;; test if v is declared as argument for lambda
804 (let* ((thirdv (third v))
805 (isarg (if (listp thirdv)
806 (eq (car thirdv) 'function) nil)))
807 (if isarg
808 (when (> inclosure (cadr v)) ; when we are in closure
809 (push v cconv-captured)) ; push it to captured vars
810 ;; FIXME more detailed comments needed
811 (push v cconv-captured))))))
812 (cconv-analyse-form (cadr forms) vars inclosure)
813 (setq forms (cddr forms)))
814 nil)
815
816 (`((lambda . ,_) . ,_) ; first element is lambda expression
817 (dolist (exp `((function ,(car form)) . ,(cdr form)))
818 (cconv-analyse-form exp vars inclosure))
819 nil)
820
821 (`(cond . ,cond-forms) ; cond special form
822 (dolist (exp1 cond-forms)
823 (dolist (exp2 exp1)
824 (cconv-analyse-form exp2 vars inclosure)))
825 nil)
826
827 (`(quote . ,_) nil) ; quote form
828
829 (`(function . ,_) nil) ; same as quote
830
831 (`(condition-case ,var ,protected-form . ,conditions-bodies)
832 ;condition-case
833 (cconv-analyse-form protected-form vars inclosure)
834 (dolist (exp conditions-bodies)
835 (cconv-analyse-form (cadr exp) vars inclosure))
836 nil)
837
838 (`(,(or `defconst `defvar `defsubst) ,value)
839 (cconv-analyse-form value vars inclosure))
840
841 (`(,(or `funcall `apply) ,fun . ,args)
842 ;; Here we ignore fun because
843 ;; funcall and apply are the only two
844 ;; functions where we can pass a candidate
845 ;; for lambda lifting as argument.
846 ;; So, if we see fun elsewhere, we'll
847 ;; delete it from lambda candidate list.
848
849 ;; If this funcall and the definition of fun
850 ;; are in different closures - we delete fun from
851 ;; canidate list, because it is too complicated
852 ;; to manage free variables in this case.
853 (let ((lv (assq fun cconv-lambda-candidates)))
854 (when lv
855 (when (not (eq (cadr lv) inclosure))
856 (setq cconv-lambda-candidates
857 (delq lv cconv-lambda-candidates)))))
858
859 (dolist (elm args)
860 (cconv-analyse-form elm vars inclosure))
861 nil)
862
863 (`(,_ . ,body-forms) ; first element is a function or whatever
864 (dolist (exp body-forms)
865 (cconv-analyse-form exp vars inclosure))
866 nil)
867
868 (_
869 (when (and (symbolp form)
870 (not (memq form '(nil t)))
871 (not (keywordp form))
872 (not (special-variable-p form)))
873 (let ((dv (assq form vars))) ; dv = declared and visible
874 (when dv
875 (when inclosure
876 ;; test if v is declared as argument of lambda
877 (let* ((thirddv (third dv))
878 (isarg (if (listp thirddv)
879 (eq (car thirddv) 'function) nil)))
880 (if isarg
881 ;; FIXME add detailed comments
882 (when (> inclosure (cadr dv)) ; capturing condition
883 (push dv cconv-captured))
884 (push dv cconv-captured))))
885 ; delete lambda
886 (setq cconv-lambda-candidates ; if it is found here
887 (delq dv cconv-lambda-candidates)))))
888 nil)))
889
890(provide 'cconv)
891;;; cconv.el ends here
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 24ea0a3e801..7990df264a9 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -1,3 +1,4 @@
1;;; -*- lexical-binding: t -*-
1;;; pcase.el --- ML-style pattern-matching macro for Elisp 2;;; pcase.el --- ML-style pattern-matching macro for Elisp
2 3
3;; Copyright (C) 2010-2011 Free Software Foundation, Inc. 4;; Copyright (C) 2010-2011 Free Software Foundation, Inc.
@@ -501,15 +502,14 @@ and otherwise defers to REST which is a list of branches of the form
501 ;; `(PAT3 . PAT4)) which the programmer can easily rewrite 502 ;; `(PAT3 . PAT4)) which the programmer can easily rewrite
502 ;; to the more efficient `(,(and PAT1 PAT3) . ,(and PAT2 PAT4))). 503 ;; to the more efficient `(,(and PAT1 PAT3) . ,(and PAT2 PAT4))).
503 (pcase--u1 `((match ,sym . ,(cadr upat))) 504 (pcase--u1 `((match ,sym . ,(cadr upat)))
504 (lexical-let ((rest rest)) 505 ;; FIXME: This codegen is not careful to share its
505 ;; FIXME: This codegen is not careful to share its 506 ;; code if used several times: code blow up is likely.
506 ;; code if used several times: code blow up is likely. 507 (lambda (vars)
507 (lambda (vars) 508 ;; `vars' will likely contain bindings which are
508 ;; `vars' will likely contain bindings which are 509 ;; not always available in other paths to
509 ;; not always available in other paths to 510 ;; `rest', so there' no point trying to pass
510 ;; `rest', so there' no point trying to pass 511 ;; them down.
511 ;; them down. 512 (pcase--u rest))
512 (pcase--u rest)))
513 vars 513 vars
514 (list `((and . ,matches) ,code . ,vars)))) 514 (list `((and . ,matches) ,code . ,vars))))
515 (t (error "Unknown upattern `%s'" upat))))) 515 (t (error "Unknown upattern `%s'" upat)))))
diff --git a/lisp/mpc.el b/lisp/mpc.el
index 8feddf8829b..4f21a162c08 100644
--- a/lisp/mpc.el
+++ b/lisp/mpc.el
@@ -1,3 +1,4 @@
1;;; -*- lexical-binding: t -*-
1;;; mpc.el --- A client for the Music Player Daemon -*- coding: utf-8 -*- 2;;; mpc.el --- A client for the Music Player Daemon -*- coding: utf-8 -*-
2 3
3;; Copyright (C) 2006-2011 Free Software Foundation, Inc. 4;; Copyright (C) 2006-2011 Free Software Foundation, Inc.
@@ -341,9 +342,7 @@ CMD can be a string which is passed as-is to MPD or a list of strings
341which will be concatenated with proper quoting before passing them to MPD." 342which will be concatenated with proper quoting before passing them to MPD."
342 (let ((proc (mpc-proc))) 343 (let ((proc (mpc-proc)))
343 (if (and callback (not (process-get proc 'ready))) 344 (if (and callback (not (process-get proc 'ready)))
344 (lexical-let ((old (process-get proc 'callback)) 345 (let ((old (process-get proc 'callback)))
345 (callback callback)
346 (cmd cmd))
347 (process-put proc 'callback 346 (process-put proc 'callback
348 (lambda () 347 (lambda ()
349 (funcall old) 348 (funcall old)
@@ -359,8 +358,7 @@ which will be concatenated with proper quoting before passing them to MPD."
359 (mapconcat 'mpc--proc-quote-string cmd " ")) 358 (mapconcat 'mpc--proc-quote-string cmd " "))
360 "\n"))) 359 "\n")))
361 (if callback 360 (if callback
362 (lexical-let ((buf (current-buffer)) 361 (let ((buf (current-buffer)))
363 (callback callback))
364 (process-put proc 'callback 362 (process-put proc 'callback
365 callback 363 callback
366 ;; (lambda () 364 ;; (lambda ()
@@ -402,8 +400,7 @@ which will be concatenated with proper quoting before passing them to MPD."
402 400
403(defun mpc-proc-cmd-to-alist (cmd &optional callback) 401(defun mpc-proc-cmd-to-alist (cmd &optional callback)
404 (if callback 402 (if callback
405 (lexical-let ((buf (current-buffer)) 403 (let ((buf (current-buffer)))
406 (callback callback))
407 (mpc-proc-cmd cmd (lambda () 404 (mpc-proc-cmd cmd (lambda ()
408 (funcall callback (prog1 (mpc-proc-buf-to-alist 405 (funcall callback (prog1 (mpc-proc-buf-to-alist
409 (current-buffer)) 406 (current-buffer))
@@ -522,7 +519,7 @@ to call FUN for any change whatsoever.")
522 519
523(defun mpc-status-refresh (&optional callback) 520(defun mpc-status-refresh (&optional callback)
524 "Refresh `mpc-status'." 521 "Refresh `mpc-status'."
525 (lexical-let ((cb callback)) 522 (let ((cb callback))
526 (mpc-proc-cmd (mpc-proc-cmd-list '("status" "currentsong")) 523 (mpc-proc-cmd (mpc-proc-cmd-list '("status" "currentsong"))
527 (lambda () 524 (lambda ()
528 (mpc--status-callback) 525 (mpc--status-callback)
@@ -775,7 +772,7 @@ The songs are returned as alists."
775 772
776(defun mpc-cmd-pause (&optional arg callback) 773(defun mpc-cmd-pause (&optional arg callback)
777 "Pause or resume playback of the queue of songs." 774 "Pause or resume playback of the queue of songs."
778 (lexical-let ((cb callback)) 775 (let ((cb callback))
779 (mpc-proc-cmd (list "pause" arg) 776 (mpc-proc-cmd (list "pause" arg)
780 (lambda () (mpc-status-refresh) (if cb (funcall cb)))) 777 (lambda () (mpc-status-refresh) (if cb (funcall cb))))
781 (unless callback (mpc-proc-sync)))) 778 (unless callback (mpc-proc-sync))))
@@ -839,7 +836,7 @@ If PLAYLIST is t or nil or missing, use the main playlist."
839 (puthash (cons 'Playlist playlist) nil mpc--find-memoize)))) 836 (puthash (cons 'Playlist playlist) nil mpc--find-memoize))))
840 837
841(defun mpc-cmd-update (&optional arg callback) 838(defun mpc-cmd-update (&optional arg callback)
842 (lexical-let ((cb callback)) 839 (let ((cb callback))
843 (mpc-proc-cmd (if arg (list "update" arg) "update") 840 (mpc-proc-cmd (if arg (list "update" arg) "update")
844 (lambda () (mpc-status-refresh) (if cb (funcall cb)))) 841 (lambda () (mpc-status-refresh) (if cb (funcall cb))))
845 (unless callback (mpc-proc-sync)))) 842 (unless callback (mpc-proc-sync))))
@@ -2351,8 +2348,7 @@ This is used so that they can be compared with `eq', which is needed for
2351 (mpc-proc-cmd (list "seekid" songid time) 2348 (mpc-proc-cmd (list "seekid" songid time)
2352 'mpc-status-refresh)))) 2349 'mpc-status-refresh))))
2353 (let ((status (mpc-cmd-status))) 2350 (let ((status (mpc-cmd-status)))
2354 (lexical-let* ((songid (cdr (assq 'songid status))) 2351 (let* ((songid (cdr (assq 'songid status)))
2355 (step step)
2356 (time (if songid (string-to-number 2352 (time (if songid (string-to-number
2357 (cdr (assq 'time status)))))) 2353 (cdr (assq 'time status))))))
2358 (let ((timer (run-with-timer 2354 (let ((timer (run-with-timer
@@ -2389,13 +2385,12 @@ This is used so that they can be compared with `eq', which is needed for
2389 (if mpc--faster-toggle-timer 2385 (if mpc--faster-toggle-timer
2390 (mpc--faster-stop) 2386 (mpc--faster-stop)
2391 (mpc-status-refresh) (mpc-proc-sync) 2387 (mpc-status-refresh) (mpc-proc-sync)
2392 (lexical-let* ((speedup speedup) 2388 (let* (songid ;The ID of the currently ffwd/rewinding song.
2393 songid ;The ID of the currently ffwd/rewinding song. 2389 songnb ;The position of that song in the playlist.
2394 songnb ;The position of that song in the playlist. 2390 songduration ;The duration of that song.
2395 songduration ;The duration of that song. 2391 songtime ;The time of the song last time we ran.
2396 songtime ;The time of the song last time we ran. 2392 oldtime ;The timeoftheday last time we ran.
2397 oldtime ;The timeoftheday last time we ran. 2393 prevsongid) ;The song we're in the process leaving.
2398 prevsongid) ;The song we're in the process leaving.
2399 (let ((fun 2394 (let ((fun
2400 (lambda () 2395 (lambda ()
2401 (let ((newsongid (cdr (assq 'songid mpc-status))) 2396 (let ((newsongid (cdr (assq 'songid mpc-status)))
diff --git a/lisp/server.el b/lisp/server.el
index 62c59b41cee..1ee30f5bc3c 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -1,3 +1,4 @@
1;;; -*- lexical-binding: t -*-
1;;; server.el --- Lisp code for GNU Emacs running as server process 2;;; server.el --- Lisp code for GNU Emacs running as server process
2 3
3;; Copyright (C) 1986-1987, 1992, 1994-2011 Free Software Foundation, Inc. 4;; Copyright (C) 1986-1987, 1992, 1994-2011 Free Software Foundation, Inc.
@@ -335,9 +336,9 @@ If CLIENT is non-nil, add a description of it to the logged message."
335 (goto-char (point-max)) 336 (goto-char (point-max))
336 (insert (funcall server-log-time-function) 337 (insert (funcall server-log-time-function)
337 (cond 338 (cond
338 ((null client) " ") 339 ((null client) " ")
339 ((listp client) (format " %s: " (car client))) 340 ((listp client) (format " %s: " (car client)))
340 (t (format " %s: " client))) 341 (t (format " %s: " client)))
341 string) 342 string)
342 (or (bolp) (newline))))) 343 (or (bolp) (newline)))))
343 344
@@ -355,7 +356,7 @@ If CLIENT is non-nil, add a description of it to the logged message."
355 (and (process-contact proc :server) 356 (and (process-contact proc :server)
356 (eq (process-status proc) 'closed) 357 (eq (process-status proc) 'closed)
357 (ignore-errors 358 (ignore-errors
358 (delete-file (process-get proc :server-file)))) 359 (delete-file (process-get proc :server-file))))
359 (server-log (format "Status changed to %s: %s" (process-status proc) msg) proc) 360 (server-log (format "Status changed to %s: %s" (process-status proc) msg) proc)
360 (server-delete-client proc)) 361 (server-delete-client proc))
361 362
@@ -410,10 +411,10 @@ If CLIENT is non-nil, add a description of it to the logged message."
410 proc 411 proc
411 ;; See if this is the last frame for this client. 412 ;; See if this is the last frame for this client.
412 (>= 1 (let ((frame-num 0)) 413 (>= 1 (let ((frame-num 0))
413 (dolist (f (frame-list)) 414 (dolist (f (frame-list))
414 (when (eq proc (frame-parameter f 'client)) 415 (when (eq proc (frame-parameter f 'client))
415 (setq frame-num (1+ frame-num)))) 416 (setq frame-num (1+ frame-num))))
416 frame-num))) 417 frame-num)))
417 (server-log (format "server-handle-delete-frame, frame %s" frame) proc) 418 (server-log (format "server-handle-delete-frame, frame %s" frame) proc)
418 (server-delete-client proc 'noframe)))) ; Let delete-frame delete the frame later. 419 (server-delete-client proc 'noframe)))) ; Let delete-frame delete the frame later.
419 420
@@ -534,8 +535,8 @@ To force-start a server, do \\[server-force-delete] and then
534 (if (not (eq t (server-running-p server-name))) 535 (if (not (eq t (server-running-p server-name)))
535 ;; Remove any leftover socket or authentication file 536 ;; Remove any leftover socket or authentication file
536 (ignore-errors 537 (ignore-errors
537 (let (delete-by-moving-to-trash) 538 (let (delete-by-moving-to-trash)
538 (delete-file server-file))) 539 (delete-file server-file)))
539 (setq server-mode nil) ;; already set by the minor mode code 540 (setq server-mode nil) ;; already set by the minor mode code
540 (display-warning 541 (display-warning
541 'server 542 'server
@@ -590,11 +591,11 @@ server or call `M-x server-force-delete' to forcibly disconnect it.")
590 (when server-use-tcp 591 (when server-use-tcp
591 (let ((auth-key 592 (let ((auth-key
592 (loop 593 (loop
593 ;; The auth key is a 64-byte string of random chars in the 594 ;; The auth key is a 64-byte string of random chars in the
594 ;; range `!'..`~'. 595 ;; range `!'..`~'.
595 repeat 64 596 repeat 64
596 collect (+ 33 (random 94)) into auth 597 collect (+ 33 (random 94)) into auth
597 finally return (concat auth)))) 598 finally return (concat auth))))
598 (process-put server-process :auth-key auth-key) 599 (process-put server-process :auth-key auth-key)
599 (with-temp-file server-file 600 (with-temp-file server-file
600 (set-buffer-multibyte nil) 601 (set-buffer-multibyte nil)
@@ -689,31 +690,31 @@ Server mode runs a process that accepts commands from the
689 (add-to-list 'frame-inherited-parameters 'client) 690 (add-to-list 'frame-inherited-parameters 'client)
690 (let ((frame 691 (let ((frame
691 (server-with-environment (process-get proc 'env) 692 (server-with-environment (process-get proc 'env)
692 '("LANG" "LC_CTYPE" "LC_ALL" 693 '("LANG" "LC_CTYPE" "LC_ALL"
693 ;; For tgetent(3); list according to ncurses(3). 694 ;; For tgetent(3); list according to ncurses(3).
694 "BAUDRATE" "COLUMNS" "ESCDELAY" "HOME" "LINES" 695 "BAUDRATE" "COLUMNS" "ESCDELAY" "HOME" "LINES"
695 "NCURSES_ASSUMED_COLORS" "NCURSES_NO_PADDING" 696 "NCURSES_ASSUMED_COLORS" "NCURSES_NO_PADDING"
696 "NCURSES_NO_SETBUF" "TERM" "TERMCAP" "TERMINFO" 697 "NCURSES_NO_SETBUF" "TERM" "TERMCAP" "TERMINFO"
697 "TERMINFO_DIRS" "TERMPATH" 698 "TERMINFO_DIRS" "TERMPATH"
698 ;; rxvt wants these 699 ;; rxvt wants these
699 "COLORFGBG" "COLORTERM") 700 "COLORFGBG" "COLORTERM")
700 (make-frame `((window-system . nil) 701 (make-frame `((window-system . nil)
701 (tty . ,tty) 702 (tty . ,tty)
702 (tty-type . ,type) 703 (tty-type . ,type)
703 ;; Ignore nowait here; we always need to 704 ;; Ignore nowait here; we always need to
704 ;; clean up opened ttys when the client dies. 705 ;; clean up opened ttys when the client dies.
705 (client . ,proc) 706 (client . ,proc)
706 ;; This is a leftover from an earlier 707 ;; This is a leftover from an earlier
707 ;; attempt at making it possible for process 708 ;; attempt at making it possible for process
708 ;; run in the server process to use the 709 ;; run in the server process to use the
709 ;; environment of the client process. 710 ;; environment of the client process.
710 ;; It has no effect now and to make it work 711 ;; It has no effect now and to make it work
711 ;; we'd need to decide how to make 712 ;; we'd need to decide how to make
712 ;; process-environment interact with client 713 ;; process-environment interact with client
713 ;; envvars, and then to change the 714 ;; envvars, and then to change the
714 ;; C functions `child_setup' and 715 ;; C functions `child_setup' and
715 ;; `getenv_internal' accordingly. 716 ;; `getenv_internal' accordingly.
716 (environment . ,(process-get proc 'env))))))) 717 (environment . ,(process-get proc 'env)))))))
717 718
718 ;; ttys don't use the `display' parameter, but callproc.c does to set 719 ;; ttys don't use the `display' parameter, but callproc.c does to set
719 ;; the DISPLAY environment on subprocesses. 720 ;; the DISPLAY environment on subprocesses.
@@ -777,8 +778,7 @@ Server mode runs a process that accepts commands from the
777 ;; frame because input from that display will be blocked (until exiting 778 ;; frame because input from that display will be blocked (until exiting
778 ;; the minibuffer). Better exit this minibuffer right away. 779 ;; the minibuffer). Better exit this minibuffer right away.
779 ;; Similarly with recursive-edits such as the splash screen. 780 ;; Similarly with recursive-edits such as the splash screen.
780 (run-with-timer 0 nil (lexical-let ((proc proc)) 781 (run-with-timer 0 nil (lambda () (server-execute-continuation proc)))
781 (lambda () (server-execute-continuation proc))))
782 (top-level))) 782 (top-level)))
783 783
784;; We use various special properties on process objects: 784;; We use various special properties on process objects:
@@ -944,119 +944,119 @@ The following commands are accepted by the client:
944 (setq command-line-args-left 944 (setq command-line-args-left
945 (mapcar 'server-unquote-arg (split-string request " " t))) 945 (mapcar 'server-unquote-arg (split-string request " " t)))
946 (while (setq arg (pop command-line-args-left)) 946 (while (setq arg (pop command-line-args-left))
947 (cond 947 (cond
948 ;; -version CLIENT-VERSION: obsolete at birth. 948 ;; -version CLIENT-VERSION: obsolete at birth.
949 ((and (equal "-version" arg) command-line-args-left) 949 ((and (equal "-version" arg) command-line-args-left)
950 (pop command-line-args-left)) 950 (pop command-line-args-left))
951 951
952 ;; -nowait: Emacsclient won't wait for a result. 952 ;; -nowait: Emacsclient won't wait for a result.
953 ((equal "-nowait" arg) (setq nowait t)) 953 ((equal "-nowait" arg) (setq nowait t))
954 954
955 ;; -current-frame: Don't create frames. 955 ;; -current-frame: Don't create frames.
956 ((equal "-current-frame" arg) (setq use-current-frame t)) 956 ((equal "-current-frame" arg) (setq use-current-frame t))
957 957
958 ;; -display DISPLAY: 958 ;; -display DISPLAY:
959 ;; Open X frames on the given display instead of the default. 959 ;; Open X frames on the given display instead of the default.
960 ((and (equal "-display" arg) command-line-args-left) 960 ((and (equal "-display" arg) command-line-args-left)
961 (setq display (pop command-line-args-left)) 961 (setq display (pop command-line-args-left))
962 (if (zerop (length display)) (setq display nil))) 962 (if (zerop (length display)) (setq display nil)))
963 963
964 ;; -parent-id ID: 964 ;; -parent-id ID:
965 ;; Open X frame within window ID, via XEmbed. 965 ;; Open X frame within window ID, via XEmbed.
966 ((and (equal "-parent-id" arg) command-line-args-left) 966 ((and (equal "-parent-id" arg) command-line-args-left)
967 (setq parent-id (pop command-line-args-left)) 967 (setq parent-id (pop command-line-args-left))
968 (if (zerop (length parent-id)) (setq parent-id nil))) 968 (if (zerop (length parent-id)) (setq parent-id nil)))
969 969
970 ;; -window-system: Open a new X frame. 970 ;; -window-system: Open a new X frame.
971 ((equal "-window-system" arg) 971 ((equal "-window-system" arg)
972 (setq dontkill t) 972 (setq dontkill t)
973 (setq tty-name 'window-system)) 973 (setq tty-name 'window-system))
974 974
975 ;; -resume: Resume a suspended tty frame. 975 ;; -resume: Resume a suspended tty frame.
976 ((equal "-resume" arg) 976 ((equal "-resume" arg)
977 (lexical-let ((terminal (process-get proc 'terminal))) 977 (let ((terminal (process-get proc 'terminal)))
978 (setq dontkill t) 978 (setq dontkill t)
979 (push (lambda () 979 (push (lambda ()
980 (when (eq (terminal-live-p terminal) t) 980 (when (eq (terminal-live-p terminal) t)
981 (resume-tty terminal))) 981 (resume-tty terminal)))
982 commands))) 982 commands)))
983 983
984 ;; -suspend: Suspend the client's frame. (In case we 984 ;; -suspend: Suspend the client's frame. (In case we
985 ;; get out of sync, and a C-z sends a SIGTSTP to 985 ;; get out of sync, and a C-z sends a SIGTSTP to
986 ;; emacsclient.) 986 ;; emacsclient.)
987 ((equal "-suspend" arg) 987 ((equal "-suspend" arg)
988 (lexical-let ((terminal (process-get proc 'terminal))) 988 (let ((terminal (process-get proc 'terminal)))
989 (setq dontkill t)
990 (push (lambda ()
991 (when (eq (terminal-live-p terminal) t)
992 (suspend-tty terminal)))
993 commands)))
994
995 ;; -ignore COMMENT: Noop; useful for debugging emacsclient.
996 ;; (The given comment appears in the server log.)
997 ((and (equal "-ignore" arg) command-line-args-left
998 (setq dontkill t) 989 (setq dontkill t)
999 (pop command-line-args-left))) 990 (push (lambda ()
1000 991 (when (eq (terminal-live-p terminal) t)
1001 ;; -tty DEVICE-NAME TYPE: Open a new tty frame at the client. 992 (suspend-tty terminal)))
1002 ((and (equal "-tty" arg) 993 commands)))
1003 (cdr command-line-args-left)) 994
1004 (setq tty-name (pop command-line-args-left) 995 ;; -ignore COMMENT: Noop; useful for debugging emacsclient.
1005 tty-type (pop command-line-args-left) 996 ;; (The given comment appears in the server log.)
1006 dontkill (or dontkill 997 ((and (equal "-ignore" arg) command-line-args-left
1007 (not use-current-frame)))) 998 (setq dontkill t)
1008 999 (pop command-line-args-left)))
1009 ;; -position LINE[:COLUMN]: Set point to the given 1000
1010 ;; position in the next file. 1001 ;; -tty DEVICE-NAME TYPE: Open a new tty frame at the client.
1011 ((and (equal "-position" arg) 1002 ((and (equal "-tty" arg)
1012 command-line-args-left 1003 (cdr command-line-args-left))
1013 (string-match "\\+\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?" 1004 (setq tty-name (pop command-line-args-left)
1014 (car command-line-args-left))) 1005 tty-type (pop command-line-args-left)
1015 (setq arg (pop command-line-args-left)) 1006 dontkill (or dontkill
1016 (setq filepos 1007 (not use-current-frame))))
1017 (cons (string-to-number (match-string 1 arg)) 1008
1018 (string-to-number (or (match-string 2 arg) ""))))) 1009 ;; -position LINE[:COLUMN]: Set point to the given
1019 1010 ;; position in the next file.
1020 ;; -file FILENAME: Load the given file. 1011 ((and (equal "-position" arg)
1021 ((and (equal "-file" arg) 1012 command-line-args-left
1022 command-line-args-left) 1013 (string-match "\\+\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?"
1023 (let ((file (pop command-line-args-left))) 1014 (car command-line-args-left)))
1024 (if coding-system 1015 (setq arg (pop command-line-args-left))
1025 (setq file (decode-coding-string file coding-system))) 1016 (setq filepos
1026 (setq file (expand-file-name file dir)) 1017 (cons (string-to-number (match-string 1 arg))
1027 (push (cons file filepos) files) 1018 (string-to-number (or (match-string 2 arg) "")))))
1028 (server-log (format "New file: %s %s" 1019
1029 file (or filepos "")) proc)) 1020 ;; -file FILENAME: Load the given file.
1030 (setq filepos nil)) 1021 ((and (equal "-file" arg)
1031 1022 command-line-args-left)
1032 ;; -eval EXPR: Evaluate a Lisp expression. 1023 (let ((file (pop command-line-args-left)))
1033 ((and (equal "-eval" arg)
1034 command-line-args-left)
1035 (if use-current-frame
1036 (setq use-current-frame 'always))
1037 (lexical-let ((expr (pop command-line-args-left)))
1038 (if coding-system
1039 (setq expr (decode-coding-string expr coding-system)))
1040 (push (lambda () (server-eval-and-print expr proc))
1041 commands)
1042 (setq filepos nil)))
1043
1044 ;; -env NAME=VALUE: An environment variable.
1045 ((and (equal "-env" arg) command-line-args-left)
1046 (let ((var (pop command-line-args-left)))
1047 ;; XXX Variables should be encoded as in getenv/setenv.
1048 (process-put proc 'env
1049 (cons var (process-get proc 'env)))))
1050
1051 ;; -dir DIRNAME: The cwd of the emacsclient process.
1052 ((and (equal "-dir" arg) command-line-args-left)
1053 (setq dir (pop command-line-args-left))
1054 (if coding-system 1024 (if coding-system
1055 (setq dir (decode-coding-string dir coding-system))) 1025 (setq file (decode-coding-string file coding-system)))
1056 (setq dir (command-line-normalize-file-name dir))) 1026 (setq file (expand-file-name file dir))
1057 1027 (push (cons file filepos) files)
1058 ;; Unknown command. 1028 (server-log (format "New file: %s %s"
1059 (t (error "Unknown command: %s" arg)))) 1029 file (or filepos "")) proc))
1030 (setq filepos nil))
1031
1032 ;; -eval EXPR: Evaluate a Lisp expression.
1033 ((and (equal "-eval" arg)
1034 command-line-args-left)
1035 (if use-current-frame
1036 (setq use-current-frame 'always))
1037 (let ((expr (pop command-line-args-left)))
1038 (if coding-system
1039 (setq expr (decode-coding-string expr coding-system)))
1040 (push (lambda () (server-eval-and-print expr proc))
1041 commands)
1042 (setq filepos nil)))
1043
1044 ;; -env NAME=VALUE: An environment variable.
1045 ((and (equal "-env" arg) command-line-args-left)
1046 (let ((var (pop command-line-args-left)))
1047 ;; XXX Variables should be encoded as in getenv/setenv.
1048 (process-put proc 'env
1049 (cons var (process-get proc 'env)))))
1050
1051 ;; -dir DIRNAME: The cwd of the emacsclient process.
1052 ((and (equal "-dir" arg) command-line-args-left)
1053 (setq dir (pop command-line-args-left))
1054 (if coding-system
1055 (setq dir (decode-coding-string dir coding-system)))
1056 (setq dir (command-line-normalize-file-name dir)))
1057
1058 ;; Unknown command.
1059 (t (error "Unknown command: %s" arg))))
1060 1060
1061 (setq frame 1061 (setq frame
1062 (cond 1062 (cond
@@ -1079,23 +1079,15 @@ The following commands are accepted by the client:
1079 1079
1080 (process-put 1080 (process-put
1081 proc 'continuation 1081 proc 'continuation
1082 (lexical-let ((proc proc) 1082 (lambda ()
1083 (files files) 1083 (with-current-buffer (get-buffer-create server-buffer)
1084 (nowait nowait) 1084 ;; Use the same cwd as the emacsclient, if possible, so
1085 (commands commands) 1085 ;; relative file names work correctly, even in `eval'.
1086 (dontkill dontkill) 1086 (let ((default-directory
1087 (frame frame) 1087 (if (and dir (file-directory-p dir))
1088 (dir dir) 1088 dir default-directory)))
1089 (tty-name tty-name)) 1089 (server-execute proc files nowait commands
1090 (lambda () 1090 dontkill frame tty-name)))))
1091 (with-current-buffer (get-buffer-create server-buffer)
1092 ;; Use the same cwd as the emacsclient, if possible, so
1093 ;; relative file names work correctly, even in `eval'.
1094 (let ((default-directory
1095 (if (and dir (file-directory-p dir))
1096 dir default-directory)))
1097 (server-execute proc files nowait commands
1098 dontkill frame tty-name))))))
1099 1091
1100 (when (or frame files) 1092 (when (or frame files)
1101 (server-goto-toplevel proc)) 1093 (server-goto-toplevel proc))
@@ -1372,12 +1364,12 @@ If invoked with a prefix argument, or if there is no server process running,
1372starts server process and that is all. Invoked by \\[server-edit]." 1364starts server process and that is all. Invoked by \\[server-edit]."
1373 (interactive "P") 1365 (interactive "P")
1374 (cond 1366 (cond
1375 ((or arg 1367 ((or arg
1376 (not server-process) 1368 (not server-process)
1377 (memq (process-status server-process) '(signal exit))) 1369 (memq (process-status server-process) '(signal exit)))
1378 (server-mode 1)) 1370 (server-mode 1))
1379 (server-clients (apply 'server-switch-buffer (server-done))) 1371 (server-clients (apply 'server-switch-buffer (server-done)))
1380 (t (message "No server editing buffers exist")))) 1372 (t (message "No server editing buffers exist"))))
1381 1373
1382(defun server-switch-buffer (&optional next-buffer killed-one filepos) 1374(defun server-switch-buffer (&optional next-buffer killed-one filepos)
1383 "Switch to another buffer, preferably one that has a client. 1375 "Switch to another buffer, preferably one that has a client.