source: trunk/abcl/src/org/armedbear/lisp/precompiler.lisp @ 14066

Last change on this file since 14066 was 14066, checked in by ehuelsmann, 9 years ago

Fix #168: compilation of LET-PLUS fails.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 43.5 KB
Line 
1;;; precompiler.lisp
2;;;
3;;; Copyright (C) 2003-2008 Peter Graves <peter@armedbear.org>
4;;; $Id: precompiler.lisp 14066 2012-08-08 21:49:40Z ehuelsmann $
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19;;;
20;;; As a special exception, the copyright holders of this library give you
21;;; permission to link this library with independent modules to produce an
22;;; executable, regardless of the license terms of these independent
23;;; modules, and to copy and distribute the resulting executable under
24;;; terms of your choice, provided that you also meet, for each linked
25;;; independent module, the terms and conditions of the license of that
26;;; module.  An independent module is a module which is not derived from
27;;; or based on this library.  If you modify this library, you may extend
28;;; this exception to your version of the library, but you are not
29;;; obligated to do so.  If you do not wish to do so, delete this
30;;; exception statement from your version.
31
32(in-package "SYSTEM")
33
34
35(export '(process-optimization-declarations
36          inline-p notinline-p inline-expansion expand-inline
37          *defined-functions* *undefined-functions* note-name-defined))
38
39(declaim (ftype (function (t) t) process-optimization-declarations))
40(defun process-optimization-declarations (forms)
41  (dolist (form forms)
42    (unless (and (consp form) (eq (%car form) 'DECLARE))
43      (return))
44    (dolist (decl (%cdr form))
45      (case (car decl)
46        (OPTIMIZE
47         (dolist (spec (%cdr decl))
48           (let ((val 3)
49                 (quality spec))
50             (when (consp spec)
51               (setf quality (%car spec)
52                     val (cadr spec)))
53             (when (and (fixnump val)
54                        (<= 0 val 3))
55               (case quality
56                 (speed
57                  (setf *speed* val))
58                 (safety
59                  (setf *safety* val))
60                 (debug
61                  (setf *debug* val))
62                 (space
63                  (setf *space* val))
64                 (compilation-speed) ;; Ignored.
65                 (t
66                  (compiler-warn "Ignoring unknown optimization quality ~S in ~S." quality decl)))))))
67        ((INLINE NOTINLINE)
68         (dolist (symbol (%cdr decl))
69           (push (cons symbol (%car decl)) *inline-declarations*)))
70        (:explain
71         (dolist (spec (%cdr decl))
72           (let ((val t)
73                 (quality spec))
74             (when (consp spec)
75               (setf quality (%car spec))
76               (when (= (length spec) 2)
77                 (setf val (%cadr spec))))
78             (if val
79                 (pushnew quality *explain*)
80                 (setf *explain* (remove quality *explain*)))))))))
81  t)
82
83(declaim (ftype (function (t) t) inline-p))
84(defun inline-p (name)
85  (declare (optimize speed))
86  (let ((entry (assoc name *inline-declarations* :test #'equal)))
87    (if entry
88        (eq (cdr entry) 'INLINE)
89        (and (symbolp name) (eq (get name '%inline) 'INLINE)))))
90
91(declaim (ftype (function (t) t) notinline-p))
92(defun notinline-p (name)
93  (declare (optimize speed))
94  (let ((entry (assoc name *inline-declarations* :test #'equal)))
95    (if entry
96        (eq (cdr entry) 'NOTINLINE)
97        (and (symbolp name) (eq (get name '%inline) 'NOTINLINE)))))
98
99(defun expand-inline (form expansion)
100;;   (format t "expand-inline form = ~S~%" form)
101;;   (format t "expand-inline expansion = ~S~%" expansion)
102  (let* ((op (car form))
103         (proclaimed-ftype (proclaimed-ftype op))
104         (args (cdr form))
105         (vars (cadr expansion))
106         (varlist ())
107         new-form)
108;;     (format t "op = ~S proclaimed-ftype = ~S~%" op (proclaimed-ftype op))
109    (do ((vars vars (cdr vars))
110         (args args (cdr args)))
111        ((null vars))
112      (push (list (car vars) (car args)) varlist))
113    (setf new-form (list* 'LET (nreverse varlist)
114                          (copy-tree (cddr expansion))))
115    (when proclaimed-ftype
116      (let ((result-type (ftype-result-type proclaimed-ftype)))
117        (when (and result-type
118                   (neq result-type t)
119                   (neq result-type '*))
120          (setf new-form (list 'TRULY-THE result-type new-form)))))
121;;     (format t "expand-inline new form = ~S~%" new-form)
122    new-form))
123
124(define-compiler-macro assoc (&whole form &rest args)
125  (cond ((and (= (length args) 4)
126              (eq (third args) :test)
127              (or (equal (fourth args) '(quote eq))
128                  (equal (fourth args) '(function eq))))
129         `(assq ,(first args) ,(second args)))
130        ((= (length args) 2)
131         `(assql ,(first args) ,(second args)))
132        (t form)))
133
134(define-compiler-macro member (&whole form &rest args)
135  (let ((arg1 (first args))
136        (arg2 (second args)))
137    (case (length args)
138      (2
139       `(memql ,arg1 ,arg2))
140      (4
141       (let ((arg3 (third args))
142             (arg4 (fourth args)))
143         (cond ((and (eq arg3 :test)
144                     (or (equal arg4 '(quote eq))
145                         (equal arg4 '(function eq))))
146                `(memq ,arg1 ,arg2))
147               ((and (eq arg3 :test)
148                     (or (equal arg4 '(quote eql))
149                         (equal arg4 '(function eql))
150                         (equal arg4 '(quote char=))
151                         (equal arg4 '(function char=))))
152                `(memql ,arg1 ,arg2))
153               (t
154                form))))
155      (t
156       form))))
157
158(define-compiler-macro search (&whole form &rest args)
159  (if (= (length args) 2)
160      `(simple-search ,@args)
161      form))
162
163(define-compiler-macro identity (&whole form &rest args)
164  (if (= (length args) 1)
165      `(progn ,(car args))
166      form))
167
168(defun quoted-form-p (form)
169  (and (consp form) (eq (%car form) 'QUOTE) (= (length form) 2)))
170
171(define-compiler-macro eql (&whole form &rest args)
172  (let ((first (car args))
173        (second (cadr args)))
174    (if (or (and (quoted-form-p first) (symbolp (cadr first)))
175            (and (quoted-form-p second) (symbolp (cadr second))))
176        `(eq ,first ,second)
177        form)))
178
179(define-compiler-macro not (&whole form arg)
180  (if (atom arg)
181      form
182      (let ((op (case (car arg)
183                  (>= '<)
184                  (<  '>=)
185                  (<= '>)
186                  (>  '<=)
187                  (t  nil))))
188        (if (and op (= (length arg) 3))
189            (cons op (cdr arg))
190            form))))
191
192(defun predicate-for-type (type)
193  (cdr (assq type '((ARRAY             . arrayp)
194                    (ATOM              . atom)
195                    (BIT-VECTOR        . bit-vector-p)
196                    (CHARACTER         . characterp)
197                    (COMPLEX           . complexp)
198                    (CONS              . consp)
199                    (FIXNUM            . fixnump)
200                    (FLOAT             . floatp)
201                    (FUNCTION          . functionp)
202                    (HASH-TABLE        . hash-table-p)
203                    (INTEGER           . integerp)
204                    (LIST              . listp)
205                    (NULL              . null)
206                    (NUMBER            . numberp)
207                    (NUMBER            . numberp)
208                    (PACKAGE           . packagep)
209                    (RATIONAL          . rationalp)
210                    (REAL              . realp)
211                    (SIMPLE-BIT-VECTOR . simple-bit-vector-p)
212                    (SIMPLE-STRING     . simple-string-p)
213                    (SIMPLE-VECTOR     . simple-vector-p)
214                    (STREAM            . streamp)
215                    (STRING            . stringp)
216                    (SYMBOL            . symbolp)))))
217
218(define-compiler-macro typep (&whole form &rest args)
219  (if (= (length args) 2) ; no environment arg
220      (let* ((object (%car args))
221             (type-specifier (%cadr args))
222             (type (and (consp type-specifier)
223                        (eq (%car type-specifier) 'QUOTE)
224                        (%cadr type-specifier)))
225             (predicate (and type (predicate-for-type type))))
226        (if predicate
227            `(,predicate ,object)
228            `(%typep ,@args)))
229      form))
230
231(define-compiler-macro subtypep (&whole form &rest args)
232  (if (= (length args) 2)
233      `(%subtypep ,@args)
234      form))
235
236(define-compiler-macro funcall (&whole form
237                                &environment env &rest args)
238  (let ((callee (car args)))
239    (if (and (>= *speed* *debug*)
240             (consp callee)
241             (eq (%car callee) 'function)
242             (symbolp (cadr callee))
243             (not (special-operator-p (cadr callee)))
244             (not (macro-function (cadr callee) env))
245             (memq (symbol-package (cadr callee))
246                   (list (find-package "CL") (find-package "SYS"))))
247        `(,(cadr callee) ,@(cdr args))
248        form)))
249
250(define-compiler-macro byte (size position)
251  `(cons ,size ,position))
252
253(define-compiler-macro byte-size (bytespec)
254  `(car ,bytespec))
255
256(define-compiler-macro byte-position (bytespec)
257  `(cdr ,bytespec))
258
259(define-source-transform concatenate (&whole form result-type &rest sequences)
260  (if (equal result-type '(quote STRING))
261      `(sys::concatenate-to-string (list ,@sequences))
262      form))
263
264(define-source-transform ldb (&whole form bytespec integer)
265  (if (and (consp bytespec)
266           (eq (%car bytespec) 'byte)
267           (= (length bytespec) 3))
268      (let ((size (%cadr bytespec))
269            (position (%caddr bytespec)))
270        `(%ldb ,size ,position ,integer))
271      form))
272
273(define-source-transform find (&whole form item sequence &key from-end test test-not start end key)
274  (cond ((and (>= (length form) 3) (null start) (null end))
275         (cond ((and (stringp sequence)
276                     (null from-end)
277                     (member test '(#'eql #'char=) :test #'equal)
278                     (null test-not)
279                     (null key))
280                `(string-find ,item ,sequence))
281               (t
282                (let ((item-var (gensym))
283                      (seq-var (gensym)))
284                  `(let ((,item-var ,item)
285                         (,seq-var ,sequence))
286                     (if (listp ,seq-var)
287                         (list-find* ,item-var ,seq-var ,from-end ,test ,test-not 0 (length ,seq-var) ,key)
288                         (vector-find* ,item-var ,seq-var ,from-end ,test ,test-not 0 (length ,seq-var) ,key)))))))
289        (t
290         form)))
291
292(define-source-transform adjoin (&whole form &rest args)
293  (if (= (length args) 2)
294      `(adjoin-eql ,(first args) ,(second args))
295      form))
296
297(define-source-transform format (&whole form &rest args)
298  (if (stringp (second args))
299      `(format ,(pop args) (formatter ,(pop args)) ,@args)
300      form))
301
302(define-compiler-macro catch (&whole form tag &rest args)
303  (declare (ignore tag))
304  (if (and (null (cdr args))
305           (constantp (car args)))
306      (car args)
307      form))
308
309(define-compiler-macro string= (&whole form &rest args)
310  (if (= (length args) 2)
311      `(sys::%%string= ,@args)
312      form))
313
314(define-compiler-macro <= (&whole form &rest args)
315  (cond ((and (= (length args) 3)
316              (numberp (first args))
317              (numberp (third args))
318              (= (first args) (third args)))
319         `(= ,(second args) ,(first args)))
320        (t
321         form)))
322
323
324(in-package "PRECOMPILER")
325
326;; No source-transforms and inlining in precompile-function-call
327;; No macro expansion in precompile-dolist and precompile-dotimes
328;; No macro expansion in precompile-do/do*
329;; No macro expansion in precompile-defun
330;; Special precompilation in precompile-case and precompile-cond
331;; Special precompilation in precompile-when and precompile-unless
332;; No precompilation in precompile-nth-value
333;; Special precompilation in precompile-return
334;; Special precompilation in expand-macro
335;;
336;; if *in-jvm-compile* is false
337
338(defvar *in-jvm-compile* nil)
339(defvar *precompile-env* nil)
340
341
342(declaim (ftype (function (t) t) precompile1))
343(defun precompile1 (form)
344  (cond ((symbolp form)
345         (multiple-value-bind
346               (expansion expanded)
347             (expand-macro form)
348           (if expanded
349               (precompile1 expansion)
350               form)))
351        ((atom form)
352         form)
353        (t
354         (let ((op (%car form))
355               handler)
356           (when (symbolp op)
357             (cond ((setf handler (get op 'precompile-handler))
358                    (return-from precompile1 (funcall handler form)))
359                   ((macro-function op *precompile-env*)
360                    (return-from precompile1 (precompile1 (expand-macro form))))
361                   ((special-operator-p op)
362                    (error "PRECOMPILE1: unsupported special operator ~S." op))))
363           (precompile-function-call form)))))
364
365(defun precompile-identity (form)
366  (declare (optimize speed))
367  form)
368
369(declaim (ftype (function (t) cons) precompile-cons))
370(defun precompile-cons (form)
371  (cons (car form) (mapcar #'precompile1 (cdr form))))
372
373(declaim (ftype (function (t t) t) precompile-function-call))
374(defun precompile-function-call (form)
375  (let ((op (car form)))
376    (when (and (consp op) (eq (%car op) 'LAMBDA))
377      (return-from precompile-function-call
378                   (cons (precompile-lambda op)
379                         (mapcar #'precompile1 (cdr form)))))
380    (when (or (not *in-jvm-compile*) (notinline-p op))
381      (return-from precompile-function-call (precompile-cons form)))
382    (when (source-transform op)
383      (let ((new-form (expand-source-transform form)))
384        (when (neq new-form form)
385          (return-from precompile-function-call (precompile1 new-form)))))
386    (when *enable-inline-expansion*
387      (let ((expansion (inline-expansion op)))
388        (when expansion
389          (let ((explain *explain*))
390            (when (and explain (memq :calls explain))
391              (format t ";   inlining call to ~S~%" op)))
392          (return-from precompile-function-call (precompile1 (expand-inline form expansion))))))
393    (cons op (mapcar #'precompile1 (cdr form)))))
394
395(defun precompile-locally (form)
396  (let ((*inline-declarations* *inline-declarations*))
397    (process-optimization-declarations (cdr form))
398  (cons 'LOCALLY (mapcar #'precompile1 (cdr form)))))
399
400(defun precompile-block (form)
401  (let ((args (cdr form)))
402    (if (null (cdr args))
403        nil
404        (list* 'BLOCK (car args) (mapcar #'precompile1 (cdr args))))))
405
406(defun precompile-dolist (form)
407  (if *in-jvm-compile*
408      (precompile1 (macroexpand form *precompile-env*))
409      (cons 'DOLIST (cons (mapcar #'precompile1 (cadr form))
410                          (mapcar #'precompile1 (cddr form))))))
411
412(defun precompile-dotimes (form)
413  (if *in-jvm-compile*
414      (precompile1 (macroexpand form *precompile-env*))
415      (cons 'DOTIMES (cons (mapcar #'precompile1 (cadr form))
416                           (mapcar #'precompile1 (cddr form))))))
417
418(defun precompile-do/do*-vars (varlist)
419  (let ((result nil))
420    (dolist (varspec varlist)
421      (if (atom varspec)
422          (push varspec result)
423          (case (length varspec)
424            (1
425             (push (%car varspec) result))
426            (2
427             (let* ((var (%car varspec))
428                    (init-form (%cadr varspec)))
429               (unless (symbolp var)
430                 (error 'type-error))
431               (push (list var (precompile1 init-form))
432                     result)))
433            (3
434             (let* ((var (%car varspec))
435                    (init-form (%cadr varspec))
436                    (step-form (%caddr varspec)))
437               (unless (symbolp var)
438                 (error 'type-error))
439               (push (list var (precompile1 init-form) (precompile1 step-form))
440                     result))))))
441    (nreverse result)))
442
443(defun precompile-do/do*-end-form (end-form)
444  (let ((end-test-form (car end-form))
445        (result-forms (cdr end-form)))
446    (list* end-test-form (mapcar #'precompile1 result-forms))))
447
448(defun precompile-do/do* (form)
449  (if *in-jvm-compile*
450      (precompile1 (macroexpand form *precompile-env*))
451      (list* (car form)
452             (precompile-do/do*-vars (cadr form))
453             (precompile-do/do*-end-form (caddr form))
454             (mapcar #'precompile1 (cdddr form)))))
455
456(defun precompile-do-symbols (form)
457  (list* (car form) (cadr form) (mapcar #'precompile1 (cddr form))))
458
459(defun precompile-load-time-value (form)
460  form)
461
462(defun precompile-progn (form)
463  (let ((body (cdr form)))
464    (if (eql (length body) 1)
465        (let ((res (precompile1 (%car body))))
466          ;; If the result turns out to be a bare symbol, leave it wrapped
467          ;; with PROGN so it won't be mistaken for a tag in an enclosing
468          ;; TAGBODY.
469          (if (symbolp res)
470              (list 'progn res)
471              res))
472        (cons 'PROGN (mapcar #'precompile1 body)))))
473
474(defun precompile-threads-synchronized-on (form)
475  (cons 'threads:synchronized-on (mapcar #'precompile1 (cdr form))))
476
477(defun precompile-progv (form)
478  (if (< (length form) 3)
479      (error "Not enough arguments for ~S." 'progv)
480      (list* 'PROGV (mapcar #'precompile1 (%cdr form)))))
481
482(defun precompile-setf (form)
483  (let ((place (second form)))
484    (cond ((and (consp place)
485                (eq (%car place) 'VALUES))
486     (setf form
487     (list* 'SETF
488      (list* 'VALUES
489             (mapcar #'precompile1 (%cdr place)))
490      (cddr form)))
491     (precompile1 (expand-macro form)))
492    ((symbolp place)
493           (multiple-value-bind
494                 (expansion expanded)
495               ;; Expand once in case the form expands
496               ;; into something that needs special
497               ;; SETF treatment
498               (macroexpand-1 place)
499             (if expanded
500                 (precompile1 (list* 'SETF expansion
501                                     (cddr form)))
502                 (precompile1 (expand-macro form)))))
503          (t
504           (precompile1 (expand-macro form))))))
505
506(defun precompile-setq (form)
507  (let* ((args (cdr form))
508         (len (length args)))
509    (when (oddp len)
510      (error 'simple-program-error
511             :format-control "Odd number of arguments to SETQ."))
512    (if (= len 2)
513        (let* ((sym (%car args))
514               (val (%cadr args)))
515          (multiple-value-bind
516                (expansion expanded)
517              ;; Expand once in case the form expands
518              ;; into something that needs special
519              ;; SETF treatment
520              (macroexpand-1 sym)
521            (if expanded
522                (precompile1 (list 'SETF expansion val))
523                (list 'SETQ sym (precompile1 val)))))
524        (let ((result ()))
525          (loop
526            (when (null args)
527              (return))
528            (push (precompile-setq (list 'SETQ (car args) (cadr args))) result)
529            (setq args (cddr args)))
530          (setq result (nreverse result))
531          (push 'PROGN result)
532          result))))
533
534(defun precompile-psetf (form)
535  (setf form
536        (list* 'PSETF
537               (mapcar #'precompile1 (cdr form))))
538  (precompile1 (expand-macro form)))
539
540(defun precompile-psetq (form)
541  ;; Make sure all the vars are symbols.
542  (do* ((rest (cdr form) (cddr rest))
543        (var (car rest)))
544       ((null rest))
545    (unless (symbolp var)
546      (error 'simple-error
547             :format-control "~S is not a symbol."
548             :format-arguments (list var))))
549  ;; Delegate to PRECOMPILE-PSETF so symbol macros are handled correctly.
550  (precompile-psetf form))
551
552
553(defun precompile-lambda-list (form)
554  (let (new aux-tail)
555    (dolist (arg form (nreverse new))
556       (if (or (atom arg) (> 2 (length arg)))
557           (progn
558             (when (eq arg '&aux)
559               (setf aux-tail t))
560             (push arg new))
561          ;; must be a cons of more than 1 cell
562          (let ((new-arg (copy-list arg)))
563            (unless (<= 1 (length arg) (if aux-tail 2 3))
564              ;; the aux-vars have a maximum length of 2 conses
565              ;; optional and key vars may have 3
566              (error 'program-error
567                     :format-control
568                     "The ~A binding specification ~S is invalid."
569                     :format-arguments (list (if aux-tail "&AUX"
570                                                 "&OPTIONAL/&KEY") arg)))
571             (setf (second new-arg)
572                   (precompile1 (second arg)))
573             (push new-arg new))))))
574
575(defun extract-lambda-vars (lambda-list)
576  (let ((state :required)
577        vars)
578    (dolist (var/key lambda-list vars)
579      (cond
580        ((eq '&aux var/key)       (setf state :aux))
581        ((eq '&key var/key)       (setf state :key))
582        ((eq '&optional var/key)  (setf state :optional))
583        ((eq '&rest var/key)      (setf state :rest))
584        ((symbolp var/key)        (unless (eq var/key '&allow-other-keys)
585                                    (push var/key vars)))
586        ((and (consp var/key)
587              (member state '(:optional :key)))
588         (setf var/key (car var/key))
589         (when (and (consp var/key) (eq state :key))
590           (setf var/key (second var/key)))
591         (if (symbolp var/key)
592             (push var/key vars)
593             (error 'program-error
594                    :format-control
595                    "Unexpected ~A variable specifier ~A."
596                    :format-arguments (list state var/key))))
597        ((and (consp var/key) (eq state :aux))
598         (if (symbolp (car var/key))
599             (push (car var/key) vars)
600             (error 'program-error
601                    :format-control "Unexpected &AUX format for ~A."
602                    :format-arguments (list var/key))))
603        (t
604         (error 'program-error
605                :format-control "Unexpected lambda-list format: ~A."
606                :format-arguments (list lambda-list)))))))
607
608(defun precompile-lambda (form)
609  (let ((body (cddr form))
610        (precompiled-lambda-list
611           (precompile-lambda-list (cadr form)))
612        (*inline-declarations* *inline-declarations*)
613        (*precompile-env* (make-environment *precompile-env*)))
614    (process-optimization-declarations body)
615    (dolist (var (extract-lambda-vars precompiled-lambda-list))
616      (environment-add-symbol-binding *precompile-env* var nil))
617    (list* 'LAMBDA precompiled-lambda-list
618           (mapcar #'precompile1 body))))
619
620(defun precompile-named-lambda (form)
621  (let ((lambda-form (list* 'LAMBDA (caddr form) (cdddr form))))
622    (let ((body (cddr lambda-form))
623          (precompiled-lambda-list
624           (precompile-lambda-list (cadr lambda-form)))
625          (*inline-declarations* *inline-declarations*)
626          (*precompile-env* (make-environment *precompile-env*)))
627      (process-optimization-declarations body)
628      (dolist (var (extract-lambda-vars precompiled-lambda-list))
629        (environment-add-symbol-binding *precompile-env* var nil))
630      (list* 'NAMED-LAMBDA (cadr form) precompiled-lambda-list
631             (mapcar #'precompile1 body)))))
632
633(defun precompile-defun (form)
634  (if *in-jvm-compile*
635      (precompile1 (expand-macro form))
636      form))
637
638(defun precompile-macrolet (form)
639  (let ((*precompile-env* (make-environment *precompile-env*)))
640    (dolist (definition (cadr form))
641      (environment-add-macro-definition
642       *precompile-env*
643       (car definition)
644       (make-macro (car definition)
645                   (make-closure
646                    (make-expander-for-macrolet definition)
647                    NIL))))
648    (multiple-value-bind (body decls)
649        (parse-body (cddr form) nil)
650      `(locally ,@decls ,@(mapcar #'precompile1 body)))))
651
652(defun precompile-symbol-macrolet (form)
653  (let ((*precompile-env* (make-environment *precompile-env*))
654        (defs (cadr form)))
655    (dolist (def defs)
656      (let ((sym (car def))
657            (expansion (cadr def)))
658        (when (special-variable-p sym)
659          (error 'program-error
660                 :format-control
661                 "Attempt to bind the special variable ~S with SYMBOL-MACROLET."
662                 :format-arguments (list sym)))
663        (environment-add-symbol-binding *precompile-env*
664                                        sym
665                                        (sys::make-symbol-macro expansion))))
666    (multiple-value-bind (body decls)
667        (parse-body (cddr form) nil)
668      (when decls
669        (let ((specials ()))
670          (dolist (decl decls)
671            (when (eq (car decl) 'DECLARE)
672              (dolist (declspec (cdr decl))
673                (when (eq (car declspec) 'SPECIAL)
674                  (setf specials (append specials (cdr declspec)))))))
675          (when specials
676            (let ((syms (mapcar #'car (cadr form))))
677              (dolist (special specials)
678                (when (memq special syms)
679                  (error 'program-error
680                         :format-control
681                         "~S is a symbol-macro and may not be declared special."
682                         :format-arguments (list special))))))))
683      `(locally ,@decls ,@(mapcar #'precompile1 body)))))
684
685(defun precompile-the (form)
686  (list 'THE
687        (second form)
688        (precompile1 (third form))))
689
690(defun precompile-truly-the (form)
691  (list 'TRULY-THE
692        (second form)
693        (precompile1 (third form))))
694
695(defun precompile-let/let*-vars (vars)
696  (let ((result nil))
697    (dolist (var vars)
698      (cond ((consp var)
699             (unless (<= 1 (length var) 2)
700               (error 'program-error
701                       :format-control
702                       "The LET/LET* binding specification ~S is invalid."
703                       :format-arguments (list var)))
704             (let ((v (%car var))
705                   (expr (cadr var)))
706               (unless (symbolp v)
707                 (error 'simple-type-error
708                        :format-control "The variable ~S is not a symbol."
709                        :format-arguments (list v)))
710               (push (list v (precompile1 expr)) result)
711               (environment-add-symbol-binding *precompile-env* v nil)))
712               ;; any value will do: we just need to shadow any symbol macros
713            (t
714             (push var result)
715             (environment-add-symbol-binding *precompile-env* var nil))))
716    (nreverse result)))
717
718(defun precompile-let (form)
719  (let ((*precompile-env* (make-environment *precompile-env*)))
720    (list* 'LET
721           (precompile-let/let*-vars (cadr form))
722           (mapcar #'precompile1 (cddr form)))))
723
724;; (LET* ((X 1)) (LET* ((Y 2)) (LET* ((Z 3)) (+ X Y Z)))) =>
725;; (LET* ((X 1) (Y 2) (Z 3)) (+ X Y Z))
726(defun maybe-fold-let* (form)
727  (if (and (= (length form) 3)
728           (consp (%caddr form))
729           (eq (%car (%caddr form)) 'LET*))
730      (let ((third (maybe-fold-let* (%caddr form))))
731        (list* 'LET* (append (%cadr form) (cadr third)) (cddr third)))
732      form))
733
734(defun precompile-let* (form)
735  (setf form (maybe-fold-let* form))
736  (let ((*precompile-env* (make-environment *precompile-env*)))
737    (list* 'LET*
738           (precompile-let/let*-vars (cadr form))
739           (mapcar #'precompile1 (cddr form)))))
740
741(defun precompile-case (form)
742  (if *in-jvm-compile*
743      (precompile1 (macroexpand form *precompile-env*))
744      (let* ((keyform (cadr form))
745             (clauses (cddr form))
746             (result (list (precompile1 keyform))))
747        (dolist (clause clauses)
748          (push (precompile-case-clause clause) result))
749        (cons (car form) (nreverse result)))))
750
751(defun precompile-case-clause (clause)
752  (let ((keys (car clause))
753        (forms (cdr clause)))
754    (cons keys (mapcar #'precompile1 forms))))
755
756(defun precompile-cond (form)
757  (if *in-jvm-compile*
758      (precompile1 (macroexpand form *precompile-env*))
759      (let ((clauses (cdr form))
760            (result nil))
761        (dolist (clause clauses)
762          (push (precompile-cond-clause clause) result))
763        (cons 'COND (nreverse result)))))
764
765(defun precompile-cond-clause (clause)
766  (let ((test (car clause))
767        (forms (cdr clause)))
768    (cons (precompile1 test) (mapcar #'precompile1 forms))))
769
770(defun precompile-local-function-def (def)
771  (let ((name (car def))
772        (body (cddr def)))
773    ;; Macro names are shadowed by local functions.
774    (environment-add-function-definition *precompile-env* name body)
775    (cdr (precompile-named-lambda (list* 'NAMED-LAMBDA def)))))
776
777(defun precompile-local-functions (defs)
778  (let ((result nil))
779    (dolist (def defs (nreverse result))
780      (push (precompile-local-function-def def) result))))
781
782(defun find-use (name expression)
783  (cond ((atom expression)
784         nil)
785        ((eq (%car expression) name)
786         t)
787        ((consp name)
788         t) ;; FIXME Recognize use of SETF functions!
789        (t
790         (or (find-use name (%car expression))
791             (find-use name (%cdr expression))))))
792
793(defun precompile-flet/labels (form)
794  (let ((*precompile-env* (make-environment *precompile-env*))
795        (operator (car form))
796        (locals (cadr form))
797  body)
798    ;; first augment the environment with the newly-defined local functions
799    ;; to shadow preexisting macro definitions with the same names
800    (dolist (local locals)
801      (environment-add-function-definition *precompile-env*
802             (car local) (cddr local)))
803    ;; then precompile (thus macro-expand) the body before inspecting it
804    ;; for the use of our locals and optimizing them away
805    (setq body (mapcar #'precompile1 (cddr form)))
806    (dolist (local locals)
807      (let* ((name (car local))
808             (used-p (find-use name body)))
809        (unless used-p
810          (when (eq operator 'LABELS)
811            (dolist (local locals)
812              (when (neq name (car local))
813                (when (find-use name (cddr local))
814                  (setf used-p t)
815                  (return))
816                ;; Scope of defined function names includes
817                ;; &OPTIONAL, &KEY and &AUX parameters
818                ;; (LABELS.7B, LABELS.7C and LABELS.7D).
819                (let ((vars (or
820                             (cdr (memq '&optional (cadr local)))
821                             (cdr (memq '&key (cadr local)))
822                             (cdr (memq '&aux (cadr local))))))
823                  (when (and vars (find-use name vars)
824                             (setf used-p t)
825                             (return))))))))
826        (unless used-p
827          (format t "; Note: deleting unused local function ~A ~S~%"
828                  operator name)
829          (let* ((new-locals (remove local locals :test 'eq))
830                 (new-form
831                  (if new-locals
832                      (list* operator new-locals body)
833                      (list* 'LOCALLY body))))
834            (return-from precompile-flet/labels (precompile1 new-form))))))
835    (list* (car form)
836           (precompile-local-functions locals)
837           body)))
838
839(defun precompile-function (form)
840  (if (and (consp (cadr form)) (eq (caadr form) 'LAMBDA))
841      (list 'FUNCTION (precompile-lambda (%cadr form)))
842      form))
843
844(defun precompile-if (form)
845  (let ((args (cdr form)))
846    (case (length args)
847      (2
848       (let ((test (precompile1 (%car args))))
849         (cond ((null test)
850                nil)
851               (;;(constantp test)
852                (eq test t)
853                (precompile1 (%cadr args)))
854               (t
855                (list 'IF
856                      test
857                      (precompile1 (%cadr args)))))))
858      (3
859       (let ((test (precompile1 (%car args))))
860         (cond ((null test)
861                (precompile1 (%caddr args)))
862               (;;(constantp test)
863                (eq test t)
864                (precompile1 (%cadr args)))
865               (t
866                (list 'IF
867                      test
868                      (precompile1 (%cadr args))
869                      (precompile1 (%caddr args)))))))
870      (t
871       (error "wrong number of arguments for IF")))))
872
873(defun precompile-when (form)
874  (if *in-jvm-compile*
875      (precompile1 (macroexpand form *precompile-env*))
876      (precompile-cons form)))
877
878(defun precompile-unless (form)
879  (if *in-jvm-compile*
880      (precompile1 (macroexpand form *precompile-env*))
881      (precompile-cons form)))
882
883;; MULTIPLE-VALUE-BIND is handled explicitly by the JVM compiler.
884(defun precompile-multiple-value-bind (form)
885  (let ((vars (cadr form))
886        (values-form (caddr form))
887        (body (cdddr form))
888        (*precompile-env* (make-environment *precompile-env*)))
889    (dolist (var vars)
890      (environment-add-symbol-binding *precompile-env* var nil))
891    (list* 'MULTIPLE-VALUE-BIND
892           vars
893           (precompile1 values-form)
894           (mapcar #'precompile1 body))))
895
896;; MULTIPLE-VALUE-LIST is handled explicitly by the JVM compiler.
897(defun precompile-multiple-value-list (form)
898  (list 'MULTIPLE-VALUE-LIST (precompile1 (cadr form))))
899
900(defun precompile-nth-value (form)
901  (if *in-jvm-compile*
902      (precompile1 (macroexpand form *precompile-env*))
903      form))
904
905(defun precompile-return (form)
906  (if *in-jvm-compile*
907      (precompile1 (macroexpand form *precompile-env*))
908      (list 'RETURN (precompile1 (cadr form)))))
909
910(defun precompile-return-from (form)
911  (list 'RETURN-FROM (cadr form) (precompile1 (caddr form))))
912
913(defun precompile-tagbody (form)
914  (do ((body (cdr form) (cdr body))
915       (result ()))
916      ((null body) (cons 'TAGBODY (nreverse result)))
917    (if (atom (car body))
918        (push (car body) result)
919        (push (let* ((first-form (car body))
920                     (expanded (precompile1 first-form)))
921                (if (and (symbolp expanded)
922                         (neq expanded first-form))
923                    ;; Workaround:
924                    ;;  Since our expansion/compilation order
925                    ;;   is out of sync with the definition of
926                    ;;   TAGBODY (which requires the compiler
927                    ;;   to look for tags before expanding),
928                    ;;   we need to disguise anything which might
929                    ;;   look like a tag. We do this by wrapping
930                    ;;   it in a PROGN form.
931                    (list 'PROGN expanded)
932                    expanded)) result))))
933
934(defun precompile-eval-when (form)
935  (list* 'EVAL-WHEN (cadr form) (mapcar #'precompile1 (cddr form))))
936
937(defun precompile-unwind-protect (form)
938  (list* 'UNWIND-PROTECT
939         (precompile1 (cadr form))
940         (mapcar #'precompile1 (cddr form))))
941
942;; EXPAND-MACRO is like MACROEXPAND, but EXPAND-MACRO quits if *IN-JVM-COMPILE*
943;; is false and a macro is encountered that is also implemented as a special
944;; operator, so interpreted code can use the special operator implementation.
945(defun expand-macro (form)
946  (let (exp)
947    (loop
948       (unless *in-jvm-compile*
949         (when (and (consp form)
950                    (symbolp (%car form))
951                    (special-operator-p (%car form)))
952           (return-from expand-macro (values form exp))))
953       (multiple-value-bind (result expanded)
954           (macroexpand-1 form *precompile-env*)
955         (unless expanded
956           (return-from expand-macro (values result exp)))
957         (setf form result
958               exp t)))))
959
960(declaim (ftype (function (t t) t) precompile-form))
961(defun precompile-form (form in-jvm-compile
962                        &optional precompile-env)
963  (let ((*in-jvm-compile* in-jvm-compile)
964        (*inline-declarations* *inline-declarations*)
965        (pre::*precompile-env* precompile-env))
966    (precompile1 form)))
967
968(defun install-handler (symbol &optional handler)
969  (declare (type symbol symbol))
970  (let ((handler (or handler
971                     (find-symbol (sys::%format nil "PRECOMPILE-~A"
972                                                (symbol-name symbol))
973                                  'precompiler))))
974    (unless (and handler (fboundp handler))
975      (error "No handler for ~S." (let ((*package* (find-package :keyword)))
976            (format nil "~S" symbol))))
977    (setf (get symbol 'precompile-handler) handler)))
978
979(defun install-handlers ()
980  (mapcar #'install-handler '(BLOCK
981                              CASE
982                              COND
983                              DOLIST
984                              DOTIMES
985                              EVAL-WHEN
986                              FUNCTION
987                              IF
988                              LAMBDA
989                              MACROLET
990                              MULTIPLE-VALUE-BIND
991                              MULTIPLE-VALUE-LIST
992                              NAMED-LAMBDA
993                              NTH-VALUE
994                              PROGN
995                              PROGV
996                              PSETF
997                              PSETQ
998                              RETURN
999                              RETURN-FROM
1000                              SETF
1001                              SETQ
1002                              SYMBOL-MACROLET
1003                              TAGBODY
1004                              UNWIND-PROTECT
1005                              UNLESS
1006                              WHEN))
1007
1008  (dolist (pair '((ECASE                precompile-case)
1009
1010                  (AND                  precompile-cons)
1011                  (OR                   precompile-cons)
1012
1013                  (CATCH                precompile-cons)
1014                  (MULTIPLE-VALUE-CALL  precompile-cons)
1015                  (MULTIPLE-VALUE-PROG1 precompile-cons)
1016
1017                  (DO                   precompile-do/do*)
1018                  (DO*                  precompile-do/do*)
1019
1020                  (LET                  precompile-let)
1021                  (LET*                 precompile-let*)
1022
1023                  (LOCALLY              precompile-locally)
1024
1025                  (FLET                 precompile-flet/labels)
1026                  (LABELS               precompile-flet/labels)
1027
1028                  (LOAD-TIME-VALUE      precompile-load-time-value)
1029
1030                  (DECLARE              precompile-identity)
1031                  (DEFUN                precompile-defun)
1032                  (GO                   precompile-identity)
1033                  (QUOTE                precompile-identity)
1034                  (THE                  precompile-the)
1035                  (THROW                precompile-cons)
1036                  (TRULY-THE            precompile-truly-the)
1037
1038                  (THREADS:SYNCHRONIZED-ON
1039                                        precompile-threads-synchronized-on)
1040     
1041      (JVM::WITH-INLINE-CODE precompile-identity)))
1042    (install-handler (first pair) (second pair))))
1043
1044(install-handlers)
1045
1046(export '(precompile-form))
1047
1048(in-package #:ext)
1049(defun macroexpand-all (form &optional env)
1050  (precompiler:precompile-form form t env))
1051
1052(in-package #:lisp)
1053
1054(defmacro compiler-let (bindings &body forms &environment env)
1055  (let ((bindings (mapcar #'(lambda (binding)
1056                              (if (atom binding) (list binding) binding))
1057                          bindings)))
1058    (progv (mapcar #'car bindings)
1059           (mapcar #'(lambda (binding)
1060                       (eval (cadr binding))) bindings)
1061      (macroexpand-all `(progn ,@forms) env))))
1062
1063(in-package #:system)
1064
1065(defun set-function-definition (name new old)
1066  (let ((*warn-on-redefinition* nil))
1067    (sys::%set-lambda-name new name)
1068    (sys:set-call-count new (sys:call-count old))
1069    (sys::%set-arglist new (sys::arglist old))
1070    (when (macro-function name)
1071      (setf new (make-macro name new)))
1072    (if (typep old 'standard-generic-function)
1073        (mop:set-funcallable-instance-function old new)
1074        (setf (fdefinition name) new))))
1075
1076(defun precompile (name &optional definition)
1077  (unless definition
1078    (setq definition (or (and (symbolp name) (macro-function name))
1079                         (fdefinition name))))
1080  (let ((expr definition)
1081        env result
1082        (pre::*precompile-env* nil))
1083    (when (functionp definition)
1084      (multiple-value-bind (form closure-p)
1085          (function-lambda-expression definition)
1086        (unless form
1087          (return-from precompile (values nil t t)))
1088        (setq env closure-p)
1089        (setq expr form)))
1090    (unless (and (consp expr) (eq (car expr) 'lambda))
1091      (format t "Unable to precompile ~S.~%" name)
1092      (return-from precompile (values nil t t)))
1093    (setf result
1094          (sys:make-closure (precompiler:precompile-form expr nil env) env))
1095    (when (and name (functionp result))
1096      (sys::set-function-definition name result definition))
1097    (values (or name result) nil nil)))
1098
1099(defun precompile-package (pkg &key verbose)
1100  (dolist (sym (package-symbols pkg))
1101    (when (fboundp sym)
1102      (unless (special-operator-p sym)
1103        (let ((f (fdefinition sym)))
1104          (unless (compiled-function-p f)
1105            (when verbose
1106              (format t "Precompiling ~S~%" sym)
1107              (finish-output))
1108            (precompile sym))))))
1109  t)
1110
1111(defun %compile (name definition)
1112  (if (and name (fboundp name) (%typep (symbol-function name) 'generic-function))
1113      (values name nil nil)
1114      (precompile name definition)))
1115
1116;; ;; Redefine EVAL to precompile its argument.
1117;; (defun eval (form)
1118;;   (%eval (precompile-form form nil)))
1119
1120;; ;; Redefine DEFMACRO to precompile the expansion function on the fly.
1121;; (defmacro defmacro (name lambda-list &rest body)
1122;;   (let* ((form (gensym "WHOLE-"))
1123;;          (env (gensym "ENVIRONMENT-")))
1124;;     (multiple-value-bind (body decls)
1125;;         (parse-defmacro lambda-list form body name 'defmacro :environment env)
1126;;       (let ((expander `(lambda (,form ,env) ,@decls (block ,name ,body))))
1127;;         `(progn
1128;;            (let ((macro (make-macro ',name
1129;;                                     (or (precompile nil ,expander) ,expander))))
1130;;              ,@(if (special-operator-p name)
1131;;                    `((put ',name 'macroexpand-macro macro))
1132;;                    `((fset ',name macro)))
1133;;              (%set-arglist macro ',lambda-list)
1134;;              ',name))))))
1135
1136;; Make an exception just this one time...
1137(when (get 'defmacro 'macroexpand-macro)
1138  (fset 'defmacro (get 'defmacro 'macroexpand-macro))
1139  (remprop 'defmacro 'macroexpand-macro))
1140
1141(defvar *defined-functions*)
1142
1143(defvar *undefined-functions*)
1144
1145(defun note-name-defined (name)
1146  (when (boundp '*defined-functions*)
1147    (push name *defined-functions*))
1148  (when (and (boundp '*undefined-functions*) (not (null *undefined-functions*)))
1149    (setf *undefined-functions* (remove name *undefined-functions*))))
1150
1151;; Redefine DEFUN to precompile the definition on the fly.
1152(defmacro defun (name lambda-list &body body &environment env)
1153  (note-name-defined name)
1154  (multiple-value-bind (body decls doc)
1155      (parse-body body)
1156    (let* ((block-name (fdefinition-block-name name))
1157           (lambda-expression
1158            `(named-lambda ,name ,lambda-list
1159                           ,@decls
1160                           ,@(when doc `(,doc))
1161                           (block ,block-name ,@body))))
1162      (cond ((and (boundp 'jvm::*file-compilation*)
1163                  ;; when JVM.lisp isn't loaded yet, this variable isn't bound
1164                  ;; meaning that we're not trying to compile to a file:
1165                  ;; Both COMPILE and COMPILE-FILE bind this variable.
1166                  ;; This function is also triggered by MACROEXPAND, though
1167                  jvm::*file-compilation*)
1168             `(progn
1169                (fset ',name ,lambda-expression)
1170                ',name))
1171            (t
1172             (when (and env (empty-environment-p env))
1173               (setf env nil))
1174             (when (null env)
1175               (setf lambda-expression (precompiler:precompile-form lambda-expression nil)))
1176             `(prog1
1177                  (%defun ',name ,lambda-expression)
1178                ,@(when doc
1179                   `((%set-documentation ',name 'function ,doc)))))))))
1180
1181(export '(precompile))
1182
1183;;(provide "PRECOMPILER")
Note: See TracBrowser for help on using the repository browser.