1
;;; CMPFLET Flet, Labels, and Macrolet.
3
;; Copyright (C) 1994 M. Hagiya, W. Schelter, T. Yuasa
5
;; This file is part of GNU Common Lisp, herein referred to as GCL
7
;; GCL is free software; you can redistribute it and/or modify it under
8
;; the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
9
;; the Free Software Foundation; either version 2, or (at your option)
12
;; GCL is distributed in the hope that it will be useful, but WITHOUT
13
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15
;; License for more details.
17
;; You should have received a copy of the GNU Library General Public License
18
;; along with GCL; see the file COPYING. If not, write to the Free Software
19
;; Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
(in-package 'compiler)
24
(si:putprop 'flet 'c1flet 'c1special)
25
(si:putprop 'flet 'c2flet 'c2)
26
(si:putprop 'labels 'c1labels 'c1special)
27
(si:putprop 'labels 'c2labels 'c2)
28
(si:putprop 'macrolet 'c1macrolet 'c1special)
29
;;; c2macrolet is not defined, because MACROLET is replaced by PROGN
31
(si:putprop 'call-local 'c2call-local 'c2)
34
name ;;; Function name.
35
ref ;;; Referenced or not.
36
;;; During Pass1, T or NIL.
37
;;; During Pass2, the vs-address for the
38
;;; function closure, or NIL.
39
ref-ccb ;;; Cross closure reference.
40
;;; During Pass1, T or NIL.
41
;;; During Pass2, the vs-address for the
42
;;; function closure, or NIL.
43
cfun ;;; The cfun for the function.
44
level ;;; The level of the function.
49
;;; During Pass 1, *funs* holds a list of fun objects, local macro definitions
50
;;; and the symbol 'CB' (Closure Boundary). 'CB' will be pushed on *funs*
51
;;; when the compiler begins to process a closure. A local macro definition
52
;;; is a list ( macro-name expansion-function).
54
(defun c1flet (args &aux body ss ts is other-decl info
55
(defs1 nil) (local-funs nil) (closures nil))
56
(when (endp args) (too-few-args 'flet 1 0))
57
(let ((*funs* *funs*))
58
(dolist** (def (car args))
60
(not (symbolp (car def)))
62
"The function definition ~s is illegal." def)
63
(let ((fun (make-fun :name (car def) :ref nil :ref-ccb nil)))
65
(push (list fun (cdr def)) defs1)))
67
(multiple-value-setq (body ss ts is other-decl) (c1body (cdr args) t))
69
(let ((*vars* *vars*))
71
(check-vdecl nil ts is)
72
(setq body (c1decl-body other-decl body)))
73
(setq info (copy-info (cadr body))))
75
(dolist* (def (reverse defs1))
76
(when (fun-ref-ccb (car def))
77
(let ((*vars* (cons 'cb *vars*))
78
(*funs* (cons 'cb *funs*))
79
(*blocks* (cons 'cb *blocks*))
80
(*tags* (cons 'cb *tags*)))
81
(let ((lam (c1lambda-expr (cadr def) (fun-name (car def)))))
82
(add-info info (cadr lam))
83
(push (list (car def) lam) closures))))
85
(when (fun-ref (car def))
86
(let ((*blocks* (cons 'lb *blocks*))
87
(*tags* (cons 'lb *tags*))
88
(*vars* (cons 'lb *vars*)))
89
(let ((lam (c1lambda-expr (cadr def) (fun-name (car def)))))
90
(add-info info (cadr lam))
91
(push (list (car def) lam) local-funs))))
93
(when (or (fun-ref (car def)) (fun-ref-ccb (car def)))
94
(setf (fun-cfun (car def)) (next-cfun)))
96
(if (or local-funs closures)
97
(list 'flet info (reverse local-funs) (reverse closures) body)
101
(defun c2flet (local-funs closures body
102
&aux (*vs* *vs*) (*clink* *clink*) (*ccb-vs* *ccb-vs*))
104
(dolist** (def local-funs)
105
(setf (fun-level (car def)) *level*)
106
(push (list nil *clink* *ccb-vs* (car def) (cadr def)) *local-funs*))
109
(dolist** (def closures)
111
(if (null *clink*) nil (cons 0 0))
112
*ccb-vs* (car def) (cadr def))
114
(push (car def) *closures*)
115
(let ((fun (car def)))
116
(declare (object fun))
117
(setf (fun-ref fun) (vs-push))
119
(wt-vs (fun-ref fun))
120
(wt "=make_cclosure_new(LC" (fun-cfun fun) ",Cnil,") (wt-clink)
123
(wt-vs (fun-ref fun))
124
(wt "=MMcons(") (wt-vs (fun-ref fun)) (wt ",") (wt-clink) (wt ");")
125
(clink (fun-ref fun))
126
(setf (fun-ref-ccb fun) (ccb-vs-push))
132
(defun c1labels (args &aux body ss ts is other-decl info
133
(defs1 nil) (local-funs nil) (closures nil)
134
(fnames nil) (processed-flag nil) (*funs* *funs*))
135
(when (endp args) (too-few-args 'labels 1 0))
137
;;; bind local-functions
138
(dolist** (def (car args))
139
(cmpck (or (endp def) (not (symbolp (car def))) (endp (cdr def)))
140
"The local function definition ~s is illegal." def)
141
(cmpck (member (car def) fnames)
142
"The function ~s was already defined." (car def))
143
(push (car def) fnames)
144
(let ((fun (make-fun :name (car def) :ref nil :ref-ccb nil)))
146
(push (list fun nil nil (cdr def)) defs1)))
148
(setq defs1 (reverse defs1))
150
;;; Now DEFS1 holds ( { ( fun-object NIL NIL body ) }* ).
152
(multiple-value-setq (body ss ts is other-decl) (c1body (cdr args) t))
153
(let ((*vars* *vars*))
155
(check-vdecl nil ts is)
156
(setq body (c1decl-body other-decl body)))
157
(setq info (copy-info (cadr body)))
161
(setq processed-flag nil)
162
(dolist** (def defs1)
163
(when (and (fun-ref (car def)) ;;; referred locally and
164
(null (cadr def))) ;;; not processed yet
165
(setq processed-flag t)
167
(let ((*blocks* (cons 'lb *blocks*))
168
(*tags* (cons 'lb *tags*))
169
(*vars* (cons 'lb *vars*)))
170
(let ((lam (c1lambda-expr (cadddr def) (fun-name (car def)))))
171
(add-info info (cadr lam))
172
(push (list (car def) lam) local-funs)))))
173
(unless processed-flag (return-from local-process))
174
)) ;;; end local process
176
(block closure-process
178
(setq processed-flag nil)
179
(dolist** (def defs1)
180
(when (and (fun-ref-ccb (car def)) ; referred across closure
181
(null (caddr def))) ; and not processed
182
(setq processed-flag t)
184
(let ((*vars* (cons 'cb *vars*))
185
(*funs* (cons 'cb *funs*))
186
(*blocks* (cons 'cb *blocks*))
187
(*tags* (cons 'cb *tags*)))
188
(let ((lam (c1lambda-expr (cadddr def) (fun-name (car def)))))
189
(add-info info (cadr lam))
190
(push (list (car def) lam) closures))))
192
(unless processed-flag (return-from closure-process))
193
)) ;;; end closure process
195
(dolist** (def defs1)
196
(when (or (fun-ref (car def)) (fun-ref-ccb (car def)))
197
(setf (fun-cfun (car def)) (next-cfun))))
199
(if (or local-funs closures)
200
(list 'labels info (reverse local-funs) (reverse closures) body)
204
(defun c2labels (local-funs closures body &aux (*vs* *vs*) (*clink* *clink*))
206
;;; Prepare for cross-referencing closures.
207
(dolist** (def closures)
208
(let ((fun (car def)))
209
(declare (object fun))
210
(setf (fun-ref fun) (vs-push))
212
(wt-vs (fun-ref fun))
213
(wt "=MMcons(Cnil,") (wt-clink) (wt ");")
214
(clink (fun-ref fun))
215
(setf (fun-ref-ccb fun) (ccb-vs-push))
218
(dolist** (def local-funs)
219
(setf (fun-level (car def)) *level*)
220
(push (list nil *clink* *ccb-vs* (car def) (cadr def)) *local-funs*))
222
;;; Then make closures.
223
(dolist** (def closures)
224
(push (list 'closure (if (null *clink*) nil (cons 0 0))
225
*ccb-vs* (car def) (cadr def))
227
(push (car def) *closures*)
229
(wt-vs* (fun-ref (car def)))
230
(wt "=make_cclosure_new(LC" (fun-cfun (car def)) ",Cnil,") (wt-clink)
234
;;; now the body of flet
239
(defun c1macrolet (args &aux body ss ts is other-decl
240
(*funs* *funs*) (*vars* *vars*))
241
(when (endp args) (too-few-args 'macrolet 1 0))
242
(dolist** (def (car args))
243
(cmpck (or (endp def) (not (symbolp (car def))) (endp (cdr def)))
244
"The macro definition ~s is illegal." def)
245
(push (list (car def)
246
(caddr (si:defmacro* (car def) (cadr def) (cddr def))))
248
(multiple-value-setq (body ss ts is other-decl) (c1body (cdr args) t))
250
(check-vdecl nil ts is)
251
(c1decl-body other-decl body)
254
(defun c1local-fun (fname &aux (ccb nil))
255
(declare (object ccb))
256
(dolist* (fun *funs* nil)
257
(cond ((eq fun 'CB) (setq ccb t))
259
(when (eq (car fun) fname) (return (cadr fun))))
260
((eq (fun-name fun) fname)
262
(setf (fun-ref-ccb fun) t)
263
(setf (fun-ref fun) t))
264
(return (list 'call-local *info* fun ccb)))))
267
(defun sch-local-fun (fname)
268
;;; Returns fun-ob for the local function (not locat macro) named FNAME,
269
;;; if any. Otherwise, returns FNAME itself.
270
(dolist* (fun *funs* fname)
271
(when (and (not (eq fun 'CB))
273
(eq (fun-name fun) fname))
277
(defun c1local-closure (fname &aux (ccb nil))
278
(declare (object ccb))
279
;;; Called only from C1FUNCTION.
280
(dolist* (fun *funs* nil)
281
(cond ((eq fun 'CB) (setq ccb t))
283
(when (eq (car fun) fname) (return (cadr fun))))
284
((eq (fun-name fun) fname)
285
(setf (fun-ref-ccb fun) t)
286
(return (list 'call-local *info* fun ccb)))))
289
(defun c2call-local (fd args &aux (*vs* *vs*))
290
;;; FD is a list ( fun-object ccb ).
294
(wt-nl "cclosure_call(") (wt-ccb-vs (fun-ref-ccb (car fd))) (wt ");"))
297
*tail-recursion-info*
298
(eq (car *tail-recursion-info*) (car fd))
300
(tail-recursion-possible)
301
(= (length args) (length (cdr *tail-recursion-info*))))
302
(let* ((*value-to-go* 'trash)
303
(*exit* (next-label))
304
(*unwind-exit* (cons *exit* *unwind-exit*)))
305
(c2psetq (mapcar #'(lambda (v) (list v nil))
306
(cdr *tail-recursion-info*))
309
(unwind-no-exit 'tail-recursion-mark)
311
(cmpnote "Tail-recursive call of ~s was replaced by iteration."
312
(fun-name (car fd))))
314
(wt-nl "L" (fun-cfun (car fd)) "(")
315
(dotimes** (n (fun-level (car fd))) (wt "base" n ","))
317
(unless (= (fun-level (car fd)) *level*) (wt (fun-level (car fd))))
320
(unwind-exit 'fun-val)