Source information goes on the $continue, not the $cont.
[bpt/guile.git] / module / language / tree-il / compile-cps.scm
CommitLineData
4fefc3a8
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
3;; Copyright (C) 2013 Free Software Foundation, Inc.
4
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19;;; Commentary:
20;;;
21;;; This pass converts Tree-IL to the continuation-passing style (CPS)
22;;; language.
23;;;
24;;; CPS is a lower-level representation than Tree-IL. Converting to
25;;; CPS, beyond adding names for all control points and all values,
26;;; simplifies expressions in the following ways, among others:
27;;;
28;;; * Fixing the order of evaluation.
29;;;
30;;; * Converting assigned variables to boxed variables.
31;;;
32;;; * Requiring that Scheme's <letrec> has already been lowered to
33;;; <fix>.
34;;;
35;;; * Inlining default-value initializers into lambda-case
36;;; expressions.
37;;;
38;;; * Inlining prompt bodies.
39;;;
40;;; * Turning toplevel and module references into primcalls. This
41;;; involves explicitly modelling the "scope" of toplevel lookups
42;;; (indicating the module with respect to which toplevel bindings
43;;; are resolved).
44;;;
45;;; The utility of CPS is that it gives a name to everything: every
46;;; intermediate value, and every control point (continuation). As such
47;;; it is more verbose than Tree-IL, but at the same time more simple as
48;;; the number of concepts is reduced.
49;;;
50;;; Code:
51
52(define-module (language tree-il compile-cps)
53 #:use-module (ice-9 match)
54 #:use-module ((srfi srfi-1) #:select (fold fold-right filter-map))
55 #:use-module (srfi srfi-26)
56 #:use-module ((system foreign) #:select (make-pointer pointer->scm))
57 #:use-module (language cps)
58 #:use-module (language cps primitives)
59 #:use-module (language tree-il analyze)
60 #:use-module (language tree-il optimize)
b7f10def 61 #:use-module ((language tree-il) #:hide (let-gensyms))
4fefc3a8
AW
62 #:export (compile-cps))
63
64;;; Guile's semantics are that a toplevel lambda captures a reference on
65;;; the current module, and that all contained lambdas use that module
66;;; to resolve toplevel variables. This parameter tracks whether or not
67;;; we are in a toplevel lambda. If we are in a lambda, the parameter
68;;; is bound to a fresh name identifying the module that was current
69;;; when the toplevel lambda is defined.
70;;;
71;;; This is more complicated than it need be. Ideally we should resolve
72;;; all toplevel bindings to bindings from specific modules, unless the
73;;; binding is unbound. This is always valid if the compilation unit
74;;; sets the module explicitly, as when compiling a module, but it
75;;; doesn't work for files auto-compiled for use with `load'.
76;;;
77(define current-topbox-scope (make-parameter #f))
78
79(define (toplevel-box src name bound? val-proc)
80 (let-gensyms (name-sym bound?-sym kbox box)
81 (build-cps-term
82 ($letconst (('name name-sym name)
83 ('bound? bound?-sym bound?))
6e422a35 84 ($letk ((kbox ($kargs ('box) (box) ,(val-proc box))))
4fefc3a8
AW
85 ,(match (current-topbox-scope)
86 (#f
87 (build-cps-term
6e422a35 88 ($continue kbox src
4fefc3a8
AW
89 ($primcall 'resolve
90 (name-sym bound?-sym)))))
91 (scope
92 (let-gensyms (scope-sym)
93 (build-cps-term
94 ($letconst (('scope scope-sym scope))
6e422a35 95 ($continue kbox src
4fefc3a8
AW
96 ($primcall 'cached-toplevel-box
97 (scope-sym name-sym bound?-sym)))))))))))))
98
99(define (module-box src module name public? bound? val-proc)
100 (let-gensyms (module-sym name-sym public?-sym bound?-sym kbox box)
101 (build-cps-term
102 ($letconst (('module module-sym module)
103 ('name name-sym name)
104 ('public? public?-sym public?)
105 ('bound? bound?-sym bound?))
6e422a35
AW
106 ($letk ((kbox ($kargs ('box) (box) ,(val-proc box))))
107 ($continue kbox src
4fefc3a8
AW
108 ($primcall 'cached-module-box
109 (module-sym name-sym public?-sym bound?-sym))))))))
110
111(define (capture-toplevel-scope src scope k)
112 (let-gensyms (module scope-sym kmodule)
113 (build-cps-term
114 ($letconst (('scope scope-sym scope))
6e422a35
AW
115 ($letk ((kmodule ($kargs ('module) (module)
116 ($continue k src
117 ($primcall 'cache-current-module!
118 (module scope-sym))))))
119 ($continue kmodule src
4fefc3a8
AW
120 ($primcall 'current-module ())))))))
121
122(define (fold-formals proc seed arity gensyms inits)
123 (match arity
124 (($ $arity req opt rest kw allow-other-keys?)
125 (let ()
126 (define (fold-req names gensyms seed)
127 (match names
128 (() (fold-opt opt gensyms inits seed))
129 ((name . names)
130 (proc name (car gensyms) #f
131 (fold-req names (cdr gensyms) seed)))))
132 (define (fold-opt names gensyms inits seed)
133 (match names
134 (() (fold-rest rest gensyms inits seed))
135 ((name . names)
136 (proc name (car gensyms) (car inits)
137 (fold-opt names (cdr gensyms) (cdr inits) seed)))))
138 (define (fold-rest rest gensyms inits seed)
139 (match rest
140 (#f (fold-kw kw gensyms inits seed))
141 (name (proc name (car gensyms) #f
142 (fold-kw kw (cdr gensyms) inits seed)))))
143 (define (fold-kw kw gensyms inits seed)
144 (match kw
145 (()
146 (unless (null? gensyms)
147 (error "too many gensyms"))
148 (unless (null? inits)
149 (error "too many inits"))
150 seed)
151 (((key name var) . kw)
152 (unless (eq? var (car gensyms))
153 (error "unexpected keyword arg order"))
154 (proc name var (car inits)
155 (fold-kw kw (cdr gensyms) (cdr inits) seed)))))
156 (fold-req req gensyms seed)))))
157
158(define (unbound? src sym kt kf)
159 (define tc8-iflag 4)
160 (define unbound-val 9)
161 (define unbound-bits (logior (ash unbound-val 8) tc8-iflag))
162 (let-gensyms (unbound ktest)
163 (build-cps-term
164 ($letconst (('unbound unbound (pointer->scm (make-pointer unbound-bits))))
6e422a35
AW
165 ($letk ((ktest ($kif kt kf)))
166 ($continue ktest src
4fefc3a8
AW
167 ($primcall 'eq? (sym unbound))))))))
168
169(define (init-default-value name sym subst init body)
170 (match (assq-ref subst sym)
171 ((subst-sym box?)
172 (let ((src (tree-il-src init)))
173 (define (maybe-box k make-body)
174 (if box?
175 (let-gensyms (kbox phi)
176 (build-cps-term
6e422a35
AW
177 ($letk ((kbox ($kargs (name) (phi)
178 ($continue k src ($primcall 'box (phi))))))
4fefc3a8
AW
179 ,(make-body kbox))))
180 (make-body k)))
181 (let-gensyms (knext kbound kunbound)
182 (build-cps-term
6e422a35 183 ($letk ((knext ($kargs (name) (subst-sym) ,body)))
4fefc3a8
AW
184 ,(maybe-box
185 knext
186 (lambda (k)
187 (build-cps-term
6e422a35
AW
188 ($letk ((kbound ($kargs () () ($continue k src ($var sym))))
189 (kunbound ($kargs () () ,(convert init k subst))))
4fefc3a8
AW
190 ,(unbound? src sym kunbound kbound))))))))))))
191
192;; exp k-name alist -> term
193(define (convert exp k subst)
194 ;; exp (v-name -> term) -> term
195 (define (convert-arg exp k)
196 (match exp
197 (($ <lexical-ref> src name sym)
198 (match (assq-ref subst sym)
199 ((box #t)
200 (let-gensyms (kunboxed unboxed)
201 (build-cps-term
6e422a35
AW
202 ($letk ((kunboxed ($kargs ('unboxed) (unboxed) ,(k unboxed))))
203 ($continue kunboxed src ($primcall 'box-ref (box)))))))
4fefc3a8
AW
204 ((subst #f) (k subst))
205 (#f (k sym))))
206 (else
6e422a35
AW
207 (let-gensyms (karg arg)
208 (build-cps-term
209 ($letk ((karg ($kargs ('arg) (arg) ,(k arg))))
210 ,(convert exp karg subst)))))))
4fefc3a8
AW
211 ;; (exp ...) ((v-name ...) -> term) -> term
212 (define (convert-args exps k)
213 (match exps
214 (() (k '()))
215 ((exp . exps)
216 (convert-arg exp
217 (lambda (name)
218 (convert-args exps
219 (lambda (names)
220 (k (cons name names)))))))))
221 (define (box-bound-var name sym body)
222 (match (assq-ref subst sym)
223 ((box #t)
224 (let-gensyms (k)
225 (build-cps-term
6e422a35
AW
226 ($letk ((k ($kargs (name) (box) ,body)))
227 ($continue k #f ($primcall 'box (sym)))))))
4fefc3a8
AW
228 (else body)))
229
230 (match exp
231 (($ <lexical-ref> src name sym)
232 (match (assq-ref subst sym)
6e422a35
AW
233 ((box #t) (build-cps-term ($continue k src ($primcall 'box-ref (box)))))
234 ((subst #f) (build-cps-term ($continue k src ($var subst))))
235 (#f (build-cps-term ($continue k src ($var sym))))))
4fefc3a8
AW
236
237 (($ <void> src)
6e422a35 238 (build-cps-term ($continue k src ($void))))
4fefc3a8
AW
239
240 (($ <const> src exp)
6e422a35 241 (build-cps-term ($continue k src ($const exp))))
4fefc3a8
AW
242
243 (($ <primitive-ref> src name)
6e422a35 244 (build-cps-term ($continue k src ($prim name))))
4fefc3a8
AW
245
246 (($ <lambda> fun-src meta body)
247 (let ()
248 (define (convert-clauses body ktail)
249 (match body
250 (#f '())
251 (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
252 (let* ((arity (make-$arity req (or opt '()) rest
253 (if kw (cdr kw) '()) (and kw (car kw))))
254 (names (fold-formals (lambda (name sym init names)
255 (cons name names))
256 '()
257 arity gensyms inits)))
258 (cons
259 (let-gensyms (kclause kargs)
260 (build-cps-cont
261 (kclause
4fefc3a8
AW
262 ($kclause ,arity
263 (kargs
4fefc3a8
AW
264 ($kargs names gensyms
265 ,(fold-formals
266 (lambda (name sym init body)
267 (if init
268 (init-default-value name sym subst init body)
269 (box-bound-var name sym body)))
270 (convert body ktail subst)
271 arity gensyms inits)))))))
272 (convert-clauses alternate ktail))))))
273 (if (current-topbox-scope)
274 (let-gensyms (kentry self ktail)
275 (build-cps-term
6e422a35
AW
276 ($continue k fun-src
277 ($fun fun-src meta '()
278 (kentry ($kentry self (ktail ($ktail))
279 ,(convert-clauses body ktail)))))))
4fefc3a8
AW
280 (let-gensyms (scope kscope)
281 (build-cps-term
6e422a35 282 ($letk ((kscope ($kargs () ()
4fefc3a8
AW
283 ,(parameterize ((current-topbox-scope scope))
284 (convert exp k subst)))))
285 ,(capture-toplevel-scope fun-src scope kscope)))))))
286
287 (($ <module-ref> src mod name public?)
288 (module-box
289 src mod name public? #t
290 (lambda (box)
6e422a35 291 (build-cps-term ($continue k src ($primcall 'box-ref (box)))))))
4fefc3a8
AW
292
293 (($ <module-set> src mod name public? exp)
294 (convert-arg exp
295 (lambda (val)
296 (module-box
297 src mod name public? #f
298 (lambda (box)
6e422a35
AW
299 (build-cps-term
300 ($continue k src ($primcall 'box-set! (box val)))))))))
4fefc3a8
AW
301
302 (($ <toplevel-ref> src name)
303 (toplevel-box
304 src name #t
305 (lambda (box)
6e422a35 306 (build-cps-term ($continue k src ($primcall 'box-ref (box)))))))
4fefc3a8
AW
307
308 (($ <toplevel-set> src name exp)
309 (convert-arg exp
310 (lambda (val)
311 (toplevel-box
312 src name #f
313 (lambda (box)
6e422a35
AW
314 (build-cps-term
315 ($continue k src ($primcall 'box-set! (box val)))))))))
4fefc3a8
AW
316
317 (($ <toplevel-define> src name exp)
318 (convert-arg exp
319 (lambda (val)
320 (let-gensyms (kname name-sym)
321 (build-cps-term
322 ($letconst (('name name-sym name))
6e422a35 323 ($continue k src ($primcall 'define! (name-sym val)))))))))
4fefc3a8
AW
324
325 (($ <call> src proc args)
326 (convert-args (cons proc args)
327 (match-lambda
328 ((proc . args)
6e422a35 329 (build-cps-term ($continue k src ($call proc args)))))))
4fefc3a8
AW
330
331 (($ <primcall> src name args)
58dee5b9
AW
332 (cond
333 ((branching-primitive? name)
334 (convert (make-conditional src exp (make-const #f #t)
335 (make-const #f #f))
336 k subst))
92afe25d
AW
337 ((and (eq? name 'vector)
338 (and-map (match-lambda
339 ((or ($ <const>)
340 ($ <void>)
341 ($ <lambda>)
342 ($ <lexical-ref>)) #t)
343 (_ #f))
344 args))
58dee5b9
AW
345 ;; Some macros generate calls to "vector" with like 300
346 ;; arguments. Since we eventually compile to make-vector and
347 ;; vector-set!, it reduces live variable pressure to allocate the
92afe25d
AW
348 ;; vector first, then set values as they are produced, if we can
349 ;; prove that no value can capture the continuation. (More on
350 ;; that caveat here:
351 ;; http://wingolog.org/archives/2013/11/02/scheme-quiz-time).
352 ;;
353 ;; Normally we would do this transformation in the compiler, but
354 ;; it's quite tricky there and quite easy here, so hold your nose
58dee5b9
AW
355 ;; while we drop some smelly code.
356 (convert (let ((len (length args)))
357 (let-gensyms (v)
358 (make-let src
359 (list 'v)
360 (list v)
361 (list (make-primcall src 'make-vector
362 (list (make-const #f len)
363 (make-const #f #f))))
364 (fold (lambda (arg n tail)
365 (make-seq
366 src
367 (make-primcall
368 src 'vector-set!
369 (list (make-lexical-ref src 'v v)
370 (make-const #f n)
371 arg))
372 tail))
373 (make-lexical-ref src 'v v)
374 (reverse args) (reverse (iota len))))))
375 k subst))
0d046513
AW
376 ((and (eq? name 'list)
377 (and-map (match-lambda
378 ((or ($ <const>)
379 ($ <void>)
380 ($ <lambda>)
381 ($ <lexical-ref>)) #t)
382 (_ #f))
383 args))
384 ;; The same situation occurs with "list".
385 (let lp ((args args) (k k))
386 (match args
387 (()
388 (build-cps-term
6e422a35 389 ($continue k src ($const '()))))
0d046513
AW
390 ((arg . args)
391 (let-gensyms (ktail tail)
392 (build-cps-term
6e422a35 393 ($letk ((ktail ($kargs ('tail) (tail)
0d046513
AW
394 ,(convert-arg arg
395 (lambda (head)
396 (build-cps-term
6e422a35 397 ($continue k src
0d046513
AW
398 ($primcall 'cons (head tail)))))))))
399 ,(lp args ktail))))))))
58dee5b9
AW
400 (else
401 (convert-args args
402 (lambda (args)
6e422a35 403 (build-cps-term ($continue k src ($primcall name args))))))))
4fefc3a8
AW
404
405 ;; Prompts with inline handlers.
406 (($ <prompt> src escape-only? tag body
407 ($ <lambda> hsrc hmeta
408 ($ <lambda-case> _ hreq #f hrest #f () hsyms hbody #f)))
409 ;; Handler:
410 ;; khargs: check args returned to handler, -> khbody
411 ;; khbody: the handler, -> k
412 ;;
413 ;; Post-body:
414 ;; krest: collect return vals from body to list, -> kpop
415 ;; kpop: pop the prompt, -> kprim
416 ;; kprim: load the values primitive, -> kret
417 ;; kret: (apply values rvals), -> k
418 ;;
419 ;; Escape prompts evaluate the body with the continuation of krest.
420 ;; Otherwise we do a no-inline call to body, continuing to krest.
421 (convert-arg tag
422 (lambda (tag)
423 (let ((hnames (append hreq (if hrest (list hrest) '()))))
424 (let-gensyms (khargs khbody kret kprim prim kpop krest vals kbody)
425 (build-cps-term
6e422a35
AW
426 ;; FIXME: Attach hsrc to $ktrunc.
427 ($letk* ((khbody ($kargs hnames hsyms
428 ,(fold box-bound-var
429 (convert hbody k subst)
430 hnames hsyms)))
431 (khargs ($ktrunc hreq hrest khbody))
432 (kpop ($kargs ('rest) (vals)
4fefc3a8 433 ($letk ((kret
4fefc3a8
AW
434 ($kargs () ()
435 ($letk ((kprim
4fefc3a8 436 ($kargs ('prim) (prim)
6e422a35 437 ($continue k src
4fefc3a8
AW
438 ($primcall 'apply
439 (prim vals))))))
6e422a35 440 ($continue kprim src
4fefc3a8 441 ($prim 'values))))))
6e422a35 442 ($continue kret src
8d59d55e 443 ($primcall 'unwind ())))))
6e422a35 444 (krest ($ktrunc '() 'rest kpop)))
4fefc3a8
AW
445 ,(if escape-only?
446 (build-cps-term
6e422a35 447 ($letk ((kbody ($kargs () ()
4fefc3a8 448 ,(convert body krest subst))))
6e422a35 449 ($continue kbody src ($prompt #t tag khargs kpop))))
4fefc3a8
AW
450 (convert-arg body
451 (lambda (thunk)
452 (build-cps-term
6e422a35
AW
453 ($letk ((kbody ($kargs () ()
454 ($continue krest (tree-il-src body)
4fefc3a8
AW
455 ($primcall 'call-thunk/no-inline
456 (thunk))))))
6e422a35 457 ($continue kbody (tree-il-src body)
96af4a18 458 ($prompt #f tag khargs kpop))))))))))))))
4fefc3a8
AW
459
460 ;; Eta-convert prompts without inline handlers.
461 (($ <prompt> src escape-only? tag body handler)
b7f10def
AW
462 (let-gensyms (h args)
463 (convert
464 (make-let
465 src (list 'h) (list h) (list handler)
466 (make-seq
467 src
468 (make-conditional
469 src
470 (make-primcall src 'procedure? (list (make-lexical-ref #f 'h h)))
471 (make-void src)
472 (make-primcall
473 src 'scm-error
474 (list
475 (make-const #f 'wrong-type-arg)
476 (make-const #f "call-with-prompt")
477 (make-const #f "Wrong type (expecting procedure): ~S")
478 (make-primcall #f 'list (list (make-lexical-ref #f 'h h)))
479 (make-primcall #f 'list (list (make-lexical-ref #f 'h h))))))
480 (make-prompt
481 src escape-only? tag body
482 (make-lambda
483 src '()
484 (make-lambda-case
485 src '() #f 'args #f '() (list args)
486 (make-primcall
487 src 'apply
488 (list (make-lexical-ref #f 'h h)
489 (make-lexical-ref #f 'args args)))
490 #f)))))
491 k
492 subst)))
4fefc3a8 493
486013d6
AW
494 (($ <abort> src tag args ($ <const> _ ()))
495 (convert-args (cons tag args)
496 (lambda (args*)
497 (build-cps-term
6e422a35
AW
498 ($continue k src
499 ($primcall 'abort-to-prompt args*))))))
486013d6 500
4fefc3a8 501 (($ <abort> src tag args tail)
486013d6
AW
502 (convert-args (append (list (make-primitive-ref #f 'abort-to-prompt)
503 tag)
504 args
505 (list tail))
4fefc3a8 506 (lambda (args*)
486013d6 507 (build-cps-term
6e422a35 508 ($continue k src ($primcall 'apply args*))))))
4fefc3a8
AW
509
510 (($ <conditional> src test consequent alternate)
511 (let-gensyms (kif kt kf)
512 (build-cps-term
6e422a35
AW
513 ($letk* ((kt ($kargs () () ,(convert consequent k subst)))
514 (kf ($kargs () () ,(convert alternate k subst)))
515 (kif ($kif kt kf)))
4fefc3a8
AW
516 ,(match test
517 (($ <primcall> src (? branching-primitive? name) args)
518 (convert-args args
519 (lambda (args)
6e422a35
AW
520 (build-cps-term
521 ($continue kif src ($primcall name args))))))
4fefc3a8
AW
522 (_ (convert-arg test
523 (lambda (test)
6e422a35
AW
524 (build-cps-term
525 ($continue kif src ($var test)))))))))))
4fefc3a8
AW
526
527 (($ <lexical-set> src name gensym exp)
528 (convert-arg exp
529 (lambda (exp)
530 (match (assq-ref subst gensym)
531 ((box #t)
532 (build-cps-term
6e422a35 533 ($continue k src ($primcall 'box-set! (box exp)))))))))
4fefc3a8
AW
534
535 (($ <seq> src head tail)
536 (let-gensyms (ktrunc kseq)
537 (build-cps-term
6e422a35
AW
538 ($letk* ((kseq ($kargs () ()
539 ,(convert tail k subst)))
540 (ktrunc ($ktrunc '() #f kseq)))
4fefc3a8
AW
541 ,(convert head ktrunc subst)))))
542
543 (($ <let> src names syms vals body)
544 (let lp ((names names) (syms syms) (vals vals))
545 (match (list names syms vals)
546 ((() () ()) (convert body k subst))
547 (((name . names) (sym . syms) (val . vals))
548 (let-gensyms (klet)
549 (build-cps-term
6e422a35
AW
550 ($letk ((klet ($kargs (name) (sym)
551 ,(box-bound-var name sym
552 (lp names syms vals)))))
4fefc3a8
AW
553 ,(convert val klet subst))))))))
554
555 (($ <fix> src names gensyms funs body)
556 ;; Some letrecs can be contified; that happens later.
557 (if (current-topbox-scope)
558 (let-gensyms (self)
559 (build-cps-term
560 ($letrec names
561 gensyms
562 (map (lambda (fun)
563 (match (convert fun k subst)
6e422a35 564 (($ $continue _ _ (and fun ($ $fun)))
4fefc3a8
AW
565 fun)))
566 funs)
567 ,(convert body k subst))))
568 (let-gensyms (scope kscope)
569 (build-cps-term
6e422a35
AW
570 ($letk ((kscope ($kargs () ()
571 ,(parameterize ((current-topbox-scope scope))
572 (convert exp k subst)))))
4fefc3a8
AW
573 ,(capture-toplevel-scope src scope kscope))))))
574
575 (($ <let-values> src exp
576 ($ <lambda-case> lsrc req #f rest #f () syms body #f))
577 (let ((names (append req (if rest (list rest) '()))))
578 (let-gensyms (ktrunc kargs)
579 (build-cps-term
6e422a35
AW
580 ($letk* ((kargs ($kargs names syms
581 ,(fold box-bound-var
582 (convert body k subst)
583 names syms)))
584 (ktrunc ($ktrunc req rest kargs)))
4fefc3a8
AW
585 ,(convert exp ktrunc subst))))))))
586
587(define (build-subst exp)
588 "Compute a mapping from lexical gensyms to substituted gensyms. The
589usual reason to replace one variable by another is assignment
590conversion. Default argument values is the other reason.
591
592Returns a list of (ORIG-SYM SUBST-SYM BOXED?). A true value for BOXED?
593indicates that the replacement variable is in a box."
594 (define (box-set-vars exp subst)
595 (match exp
596 (($ <lexical-set> src name sym exp)
597 (if (assq sym subst)
598 subst
599 (cons (list sym (gensym "b") #t) subst)))
600 (_ subst)))
601 (define (default-args exp subst)
602 (match exp
603 (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
604 (fold-formals (lambda (name sym init subst)
605 (if init
606 (let ((box? (match (assq-ref subst sym)
607 ((box #t) #t)
608 (#f #f)))
609 (subst-sym (gensym (symbol->string name))))
610 (cons (list sym subst-sym box?) subst))
611 subst))
612 subst
613 (make-$arity req (or opt '()) rest
614 (if kw (cdr kw) '()) (and kw (car kw)))
615 gensyms
616 inits))
617 (_ subst)))
618 (tree-il-fold box-set-vars default-args '() exp))
619
620(define (cps-convert/thunk exp)
621 (let ((src (tree-il-src exp)))
622 (let-gensyms (kinit init ktail kclause kbody)
623 (build-cps-exp
6e422a35
AW
624 ($fun src '() '()
625 (kinit ($kentry init
626 (ktail ($ktail))
627 ((kclause
628 ($kclause ('() '() #f '() #f)
629 (kbody ($kargs () ()
630 ,(convert exp ktail
631 (build-subst exp))))))))))))))
4fefc3a8
AW
632
633(define *comp-module* (make-fluid))
634
635(define %warning-passes
636 `((unused-variable . ,unused-variable-analysis)
637 (unused-toplevel . ,unused-toplevel-analysis)
638 (unbound-variable . ,unbound-variable-analysis)
639 (arity-mismatch . ,arity-analysis)
640 (format . ,format-analysis)))
641
642(define (optimize-tree-il x e opts)
643 (define warnings
644 (or (and=> (memq #:warnings opts) cadr)
645 '()))
646
647 ;; Go through the warning passes.
648 (let ((analyses (filter-map (lambda (kind)
649 (assoc-ref %warning-passes kind))
650 warnings)))
651 (analyze-tree analyses x e))
652
653 (optimize x e opts))
654
655(define (compile-cps exp env opts)
656 (values (cps-convert/thunk (optimize-tree-il exp env opts))
657 env
658 env))
659
660;;; Local Variables:
661;;; eval: (put 'convert-arg 'scheme-indent-function 1)
662;;; eval: (put 'convert-args 'scheme-indent-function 1)
663;;; End: