1 | ;;; compiler.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2003 Peter Graves |
---|
4 | ;;; $Id: compiler.lisp,v 1.54 2003-10-18 22:33:08 piso Exp $ |
---|
5 | ;;; |
---|
6 | ;;; This program is free software; you can redistribute it and/or |
---|
7 | ;;; modify it under the terms of the GNU General Public License |
---|
8 | ;;; as published by the Free Software Foundation; either version 2 |
---|
9 | ;;; of the License, or (at your option) any later version. |
---|
10 | ;;; |
---|
11 | ;;; This program is distributed in the hope that it will be useful, |
---|
12 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | ;;; GNU General Public License for more details. |
---|
15 | ;;; |
---|
16 | ;;; You should have received a copy of the GNU General Public License |
---|
17 | ;;; along with this program; if not, write to the Free Software |
---|
18 | ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
19 | |
---|
20 | (unless (find-package "COMPILER") |
---|
21 | (make-package "COMPILER" :nicknames '("C") :use '("COMMON-LISP"))) |
---|
22 | |
---|
23 | ;; (in-package "COMMON-LISP") |
---|
24 | |
---|
25 | ;; (export 'compile) |
---|
26 | |
---|
27 | (in-package "COMPILER") |
---|
28 | |
---|
29 | (defun compile-progn (forms) |
---|
30 | (mapcar #'compile-sexp forms)) |
---|
31 | |
---|
32 | (defun compile-setq (exprs) |
---|
33 | (when (oddp (length exprs)) |
---|
34 | (error "odd number of arguments to SETQ")) |
---|
35 | (do* ((result '(setq)) |
---|
36 | (sym (car exprs) (car exprs)) |
---|
37 | (val (cadr exprs) (cadr exprs))) |
---|
38 | ((null exprs) result) |
---|
39 | (setq result (append result (list sym) (list (compile-sexp val)))) |
---|
40 | (setq exprs (cddr exprs)))) |
---|
41 | |
---|
42 | (defun compile-cond (clauses) |
---|
43 | (let ((result nil)) |
---|
44 | (dolist (clause clauses) |
---|
45 | (setq result (nconc result (list (compile-cond-clause clause))))) |
---|
46 | result)) |
---|
47 | |
---|
48 | (defun compile-cond-clause (clause) |
---|
49 | (let ((test (car clause)) |
---|
50 | (forms (cdr clause))) |
---|
51 | (nconc (list (compile-sexp test)) (compile-progn forms)))) |
---|
52 | |
---|
53 | (defun compile-case (keyform clauses) |
---|
54 | (let ((result (list (compile-sexp keyform)))) |
---|
55 | (dolist (clause clauses) |
---|
56 | (setq result (nconc result (list (compile-case-clause clause))))) |
---|
57 | result)) |
---|
58 | |
---|
59 | (defun compile-case-clause (clause) |
---|
60 | (let ((keys (car clause)) |
---|
61 | (forms (cdr clause))) |
---|
62 | (nconc (list keys) (compile-progn forms)))) |
---|
63 | |
---|
64 | (defun compile-tagbody (body) |
---|
65 | (let ((rest body) |
---|
66 | (result ())) |
---|
67 | (do () ((null rest) result) |
---|
68 | (if (atom (car rest)) |
---|
69 | (setq result (nconc result (list (car rest)))) |
---|
70 | (setq result (append result (list (compile-sexp (car rest)))))) |
---|
71 | (setq rest (cdr rest))))) |
---|
72 | |
---|
73 | (defun compile-locals (locals) |
---|
74 | (let ((result nil)) |
---|
75 | (dolist (local locals) |
---|
76 | (setq result (append result (list (compile-local-def local))))) |
---|
77 | result)) |
---|
78 | |
---|
79 | (defun compile-local-def (def) |
---|
80 | (let ((name (car def)) |
---|
81 | (arglist (cadr def)) |
---|
82 | (body (cddr def))) |
---|
83 | (list* name arglist (compile-progn body)))) |
---|
84 | |
---|
85 | (defun compile-let-vars (vars) |
---|
86 | (let ((result nil)) |
---|
87 | (dolist (var vars) |
---|
88 | (if (consp var) |
---|
89 | (let* ((v (car var)) |
---|
90 | (expr (cadr var))) |
---|
91 | (unless (symbolp v) |
---|
92 | (error 'type-error)) |
---|
93 | (setq result (append result (list (list v (compile-sexp expr)))))) |
---|
94 | (setq result (append result (list var))))) |
---|
95 | result)) |
---|
96 | |
---|
97 | ;; (defun define-local-macro (name lambda-list &rest body) |
---|
98 | ;; (let* ((form (gensym)) |
---|
99 | ;; (env (gensym)) |
---|
100 | ;; (body (sys::parse-defmacro lambda-list form body name 'macrolet |
---|
101 | ;; :environment env)) |
---|
102 | ;; (expander `(lambda (,form ,env) (block ,name ,body)))) |
---|
103 | ;; (format t "expander = ~S~%" expander) |
---|
104 | ;; (sys::make-macro expander))) |
---|
105 | |
---|
106 | (defun define-local-macro (name lambda-list body) |
---|
107 | (let* ((form (gensym)) |
---|
108 | (env (gensym)) |
---|
109 | (body (sys::parse-defmacro lambda-list form body name 'macrolet |
---|
110 | :environment env)) |
---|
111 | (expander `(lambda (,form ,env) (block ,name ,body))) |
---|
112 | (compiled-expander (%compile nil expander))) |
---|
113 | ;; (format t "expander = ~S~%" expander) |
---|
114 | ;; (format t "compiled-expander = ~S~%" compiled-expander) |
---|
115 | (or compiled-expander expander))) |
---|
116 | |
---|
117 | (defparameter *local-macros* ()) |
---|
118 | |
---|
119 | (defun local-macro-function (name) |
---|
120 | (getf *local-macros* name)) |
---|
121 | |
---|
122 | (defun expand-local-macro (form) |
---|
123 | (let ((expansion (funcall (local-macro-function (car form)) form nil))) |
---|
124 | ;; If the expansion turns out to be a bare symbol, wrap it with PROGN so it |
---|
125 | ;; won't be mistaken for a tag in an enclosing TAGBODY. |
---|
126 | (if (symbolp expansion) |
---|
127 | (list 'progn expansion) |
---|
128 | expansion))) |
---|
129 | |
---|
130 | (defun compile-macrolet (form) |
---|
131 | (let ((*local-macros* *local-macros*) |
---|
132 | (macros (cadr form)) |
---|
133 | (body (cddr form)) |
---|
134 | (res ()) |
---|
135 | compiled-body) |
---|
136 | (dolist (macro macros) |
---|
137 | (let ((name (car macro)) |
---|
138 | (lambda-list (cadr macro)) |
---|
139 | (forms (cddr macro))) |
---|
140 | (push (define-local-macro name lambda-list forms) *local-macros*) |
---|
141 | (push name *local-macros*) |
---|
142 | (push (list* name lambda-list (compile-progn forms)) res))) |
---|
143 | ;; (format t "*local-macros* = ~S~%" *local-macros*) |
---|
144 | ;; (format t "body = ~S~%" body) |
---|
145 | (setf compiled-body (compile-progn body)) |
---|
146 | ;; (format t "compiled-body = ~S~%" compiled-body) |
---|
147 | ;; (setf res (list* 'macrolet (reverse res) compiled-body)) |
---|
148 | ;; res)) |
---|
149 | (setf res (list* 'progn compiled-body)) |
---|
150 | res)) |
---|
151 | |
---|
152 | (defun compile-special (form) |
---|
153 | (let ((first (car form))) |
---|
154 | (case first |
---|
155 | (BLOCK |
---|
156 | (unless (>= (length form) 2) |
---|
157 | (error "wrong number of arguments for BLOCK")) |
---|
158 | (unless (symbolp (cadr form)) |
---|
159 | (error 'type-error)) |
---|
160 | (list* 'block (cadr form) (mapcar #'compile-sexp (cddr form)))) |
---|
161 | (COND |
---|
162 | (cons 'cond (compile-cond (cdr form)))) |
---|
163 | (QUOTE |
---|
164 | form) |
---|
165 | ((AND OR) |
---|
166 | (cons first |
---|
167 | (mapcar #'compile-sexp (cdr form)))) |
---|
168 | (FUNCTION |
---|
169 | (if (and (consp (cadr form)) (eq (caadr form) 'setf)) |
---|
170 | form |
---|
171 | (cons 'function (list (compile-sexp (cadr form)))))) |
---|
172 | (WHEN |
---|
173 | (cons 'when (mapcar #'compile-sexp (cdr form)))) |
---|
174 | ((LET LET*) |
---|
175 | (list* first (compile-let-vars (cadr form)) (mapcar #'compile-sexp (cddr form)))) |
---|
176 | (SETQ |
---|
177 | (compile-setq (cdr form))) |
---|
178 | (PROGN |
---|
179 | (let ((body (cdr form))) |
---|
180 | (if (= (length body) 1) |
---|
181 | (let ((res (compile-sexp (car body)))) |
---|
182 | ;; If the result turns out to be a bare symbol, leave it wrapped |
---|
183 | ;; with PROGN so it won't be mistaken for a tag in an enclosing |
---|
184 | ;; TAGBODY. |
---|
185 | (if (symbolp res) |
---|
186 | (list 'progn res) |
---|
187 | res)) |
---|
188 | (cons 'progn (mapcar #'compile-sexp body))))) |
---|
189 | (IF |
---|
190 | (unless (<= 2 (length (cdr form)) 3) |
---|
191 | (error "wrong number of arguments for IF")) |
---|
192 | (cons 'if (mapcar #'compile-sexp (cdr form)))) |
---|
193 | ((CASE ECASE) |
---|
194 | (cons first (compile-case (cadr form) (cddr form)))) |
---|
195 | (DOLIST |
---|
196 | (let ((args (cadr form)) |
---|
197 | (body (cddr form))) |
---|
198 | (cons first (cons args (compile-progn body))))) |
---|
199 | ((DO DO*) |
---|
200 | (let ((second (second form)) |
---|
201 | (third (third form)) |
---|
202 | (body (cdddr form))) |
---|
203 | (list* first second third (mapcar #'compile-sexp body)))) |
---|
204 | (DOTIMES |
---|
205 | (let ((args (cadr form)) |
---|
206 | (body (cddr form))) |
---|
207 | (list* first args (compile-progn body)))) |
---|
208 | (TAGBODY |
---|
209 | (let ((body (cdr form))) |
---|
210 | (cons 'tagbody (compile-tagbody body)))) |
---|
211 | (LABELS |
---|
212 | ;; (format t "LABELS *local-macros* = ~S~%" *local-macros*) |
---|
213 | (let* ((locals (cadr form)) |
---|
214 | (body (cddr form)) |
---|
215 | (compiled-locals (compile-locals locals)) |
---|
216 | (compiled-body (compile-progn body))) |
---|
217 | ;; (format t "body = ~S~%" body) |
---|
218 | ;; (format t "compiled-body = ~S~%" compiled-body) |
---|
219 | (append '(labels) (list compiled-locals) compiled-body))) |
---|
220 | (RETURN |
---|
221 | (if (cdr form) |
---|
222 | (cons 'return (list (compile-sexp (cadr form)))) |
---|
223 | form)) |
---|
224 | (RETURN-FROM form) |
---|
225 | (UNLESS |
---|
226 | (cons 'unless (mapcar #'compile-sexp (cdr form)))) |
---|
227 | (UNWIND-PROTECT |
---|
228 | (list* 'unwind-protect (compile-sexp (cadr form)) (mapcar #'compile-sexp (cddr form)))) |
---|
229 | (MULTIPLE-VALUE-PROG1 |
---|
230 | (list* 'unwind-protect (compile-sexp (cadr form)) (mapcar #'compile-sexp (cddr form)))) |
---|
231 | (THE |
---|
232 | (compile-sexp (caddr form))) |
---|
233 | (GO form) |
---|
234 | (MACROLET |
---|
235 | (compile-macrolet form)) |
---|
236 | (MULTIPLE-VALUE-BIND |
---|
237 | (let ((vars (second form)) |
---|
238 | (values-form (third form)) |
---|
239 | (body (cdddr form))) |
---|
240 | (list* 'multiple-value-bind vars (compile-sexp values-form) |
---|
241 | (mapcar #'compile-sexp body)))) |
---|
242 | (MULTIPLE-VALUE-SETQ |
---|
243 | (list 'multiple-value-setq (second form) (compile-sexp (third form)))) |
---|
244 | (t |
---|
245 | ;; (format t "COMPILE-SPECIAL skipping ~S~%" first) |
---|
246 | form)))) |
---|
247 | |
---|
248 | ;; EXPAND-MACRO is like MACROEXPAND, but EXPAND-MACRO quits if it encounters a |
---|
249 | ;; macro that's also implemented as a special operator, so interpreted code can |
---|
250 | ;; use the (faster) special operator implementation. |
---|
251 | (defun expand-macro (form) |
---|
252 | (do () () |
---|
253 | (multiple-value-bind (result expanded) (macroexpand-1 form) |
---|
254 | (unless expanded (return-from expand-macro result)) |
---|
255 | (when (and (consp result) |
---|
256 | (symbolp (car result)) |
---|
257 | (special-operator-p (car result))) |
---|
258 | (return-from expand-macro result)) |
---|
259 | (setq form result)))) |
---|
260 | |
---|
261 | (defun compile-sexp (form) |
---|
262 | (if (atom form) form |
---|
263 | (let ((first (car form))) |
---|
264 | (when (local-macro-function first) |
---|
265 | ;; (format t "form = ~S~%" form) |
---|
266 | (let ((expansion (expand-local-macro form))) |
---|
267 | ;; (format t "expansion = ~S~%" expansion) |
---|
268 | (return-from compile-sexp expansion))) |
---|
269 | ;; (unless (and (symbolp first) (fboundp first)) |
---|
270 | ;; (return-from compile-sexp form)) |
---|
271 | (cond ((eq first 'LAMBDA) |
---|
272 | (list* 'LAMBDA (second form) |
---|
273 | (mapcar #'compile-sexp (cddr form)))) |
---|
274 | ((and (symbolp first) (special-operator-p first)) |
---|
275 | (compile-special form)) |
---|
276 | ((and (symbolp first) (macro-function first)) |
---|
277 | (compile-sexp (expand-macro form))) |
---|
278 | (t |
---|
279 | (let ((args (mapcar #'compile-sexp (cdr form)))) |
---|
280 | (cons first args))))))) |
---|
281 | |
---|
282 | (defun %compile (name &optional definition) |
---|
283 | (unless definition |
---|
284 | (setq definition (or (and (symbolp name) (macro-function name)) |
---|
285 | (fdefinition name)))) |
---|
286 | (let (expr result) |
---|
287 | (cond ((functionp definition) |
---|
288 | (multiple-value-bind (form closure-p) |
---|
289 | (function-lambda-expression definition) |
---|
290 | (unless form |
---|
291 | (format t "; No lambda expression available for ~S.~%" name) |
---|
292 | (return-from %compile (values nil t t))) |
---|
293 | (when closure-p |
---|
294 | (format t "; Unable to compile function ~S defined in non-null lexical environment.~%" name) |
---|
295 | (finish-output) |
---|
296 | (return-from %compile (values nil t t))) |
---|
297 | (setq expr form))) |
---|
298 | ((and (consp definition) (eq (car definition) 'lambda)) |
---|
299 | (setq expr definition)) |
---|
300 | (t |
---|
301 | (error 'type-error))) |
---|
302 | (setq result (sys::coerce-to-function (compile-sexp expr))) |
---|
303 | (when (and name (functionp result)) |
---|
304 | (sys::%set-lambda-name result name) |
---|
305 | (sys::%set-call-count result (sys::%call-count definition)) |
---|
306 | (sys::%set-arglist result (sys::arglist definition)) |
---|
307 | (if (and (symbolp name) (macro-function name)) |
---|
308 | (setf (fdefinition name) (sys::make-macro result)) |
---|
309 | (setf (fdefinition name) result))) |
---|
310 | (values (or name result) nil nil))) |
---|
311 | |
---|
312 | (defun compile-package (pkg &key verbose) |
---|
313 | (dolist (sym (sys::package-symbols pkg)) |
---|
314 | (when (fboundp sym) |
---|
315 | ;; (unless (or (special-operator-p sym) (macro-function sym)) |
---|
316 | (unless (special-operator-p sym) |
---|
317 | (let ((f (fdefinition sym))) |
---|
318 | (unless (compiled-function-p f) |
---|
319 | (when verbose |
---|
320 | (format t "compiling ~S~%" sym) |
---|
321 | (finish-output)) |
---|
322 | (%compile sym)))))) |
---|
323 | t) |
---|
324 | |
---|
325 | (compile-package :compiler) |
---|
326 | (compile-package :sys) |
---|
327 | (compile-package :cl) |
---|
328 | |
---|
329 | (in-package :cl) |
---|
330 | |
---|
331 | (defun compile (name &optional definition) |
---|
332 | (if (and name (fboundp name) (typep (symbol-function name) 'generic-function)) |
---|
333 | (values name nil nil) |
---|
334 | (c::%compile name definition))) |
---|
335 | |
---|
336 | ;; Redefine DEFMACRO to compile the expansion function on the fly. |
---|
337 | (defmacro defmacro (name lambda-list &rest body) |
---|
338 | (let* ((form (gensym)) |
---|
339 | (env (gensym)) |
---|
340 | (body (sys::parse-defmacro lambda-list form body name 'defmacro |
---|
341 | :environment env)) |
---|
342 | (expander `(lambda (,form ,env) (block ,name ,body)))) |
---|
343 | `(progn |
---|
344 | (if (special-operator-p ',name) |
---|
345 | (sys::%put ',name |
---|
346 | 'sys::macroexpand-macro |
---|
347 | (sys::make-macro (or (c::%compile nil ,expander) ,expander))) |
---|
348 | (sys::fset ',name |
---|
349 | (sys::make-macro (or (c::%compile nil ,expander) ,expander)))) |
---|
350 | ',name))) |
---|
351 | |
---|
352 | ;; Make an exception just this one time... |
---|
353 | (sys::fset 'defmacro (get 'defmacro 'sys::macroexpand-macro)) |
---|
354 | |
---|
355 | ;; Redefine DEFUN to compile the definition on the fly. |
---|
356 | (defmacro defun (name lambda-list &rest body &environment env) |
---|
357 | `(progn |
---|
358 | (sys::%defun ',name ',lambda-list ',body ,env) |
---|
359 | (compiler::%compile ',name) |
---|
360 | ',name)) |
---|