Remove $void CPS expression type
[bpt/guile.git] / module / language / cps.scm
CommitLineData
80b01fd0
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
a9ec16f9 3;; Copyright (C) 2013, 2014, 2015 Free Software Foundation, Inc.
80b01fd0
AW
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 is the continuation-passing style (CPS) intermediate language
22;;; (IL) for Guile.
23;;;
24;;; There are two kinds of terms in CPS: terms that bind continuations,
25;;; and terms that call continuations.
26;;;
27;;; $letk binds a set of mutually recursive continuations, each one an
6e422a35
AW
28;;; instance of $cont. A $cont declares the name of a continuation, and
29;;; then contains as a subterm the particular continuation instance:
59258f7c
AW
30;;; $kargs for continuations that bind values, $ktail for the tail
31;;; continuation, etc.
80b01fd0
AW
32;;;
33;;; $continue nodes call continuations. The expression contained in the
34;;; $continue node determines the value or values that are passed to the
35;;; target continuation: $const to pass a constant value, $values to
6e422a35 36;;; pass multiple named values, etc. $continue nodes also record the source at which
80b01fd0
AW
37;;;
38;;; Additionally there is $letrec, a term that binds mutually recursive
39;;; functions. The contification pass will turn $letrec into $letk if
40;;; it can do so. Otherwise, the closure conversion pass will desugar
41;;; $letrec into an equivalent sequence of make-closure primcalls and
42;;; subsequent initializations of the captured variables of the
43;;; closures. You can think of $letrec as pertaining to "high CPS",
44;;; whereas later passes will only see "low CPS", which does not have
45;;; $letrec.
46;;;
47;;; This particular formulation of CPS was inspired by Andrew Kennedy's
48;;; 2007 paper, "Compiling with Continuations, Continued". All Guile
49;;; hackers should read that excellent paper! As in Kennedy's paper,
50;;; continuations are second-class, and may be thought of as basic block
51;;; labels. All values are bound to variables using continuation calls:
52;;; even constants!
53;;;
54;;; There are some Guile-specific quirks as well:
55;;;
36527695 56;;; - $kreceive represents a continuation that receives multiple values,
80b01fd0
AW
57;;; but which truncates them to some number of required values,
58;;; possibly with a rest list.
59;;;
8320f504 60;;; - $kfun labels an entry point for a $fun (a function), and
80b01fd0
AW
61;;; contains a $ktail representing the formal argument which is the
62;;; function's continuation.
63;;;
8320f504 64;;; - $kfun also contain a $kclause continuation, corresponding to
90dce16d
AW
65;;; the first case-lambda clause of the function. $kclause actually
66;;; contains the clause body, and the subsequent clause (if any).
67;;; This is because the $kclause logically matches or doesn't match
68;;; a given set of actual arguments against a formal arity, then
69;;; proceeds to a "body" continuation (which is a $kargs).
80b01fd0
AW
70;;;
71;;; That's to say that a $fun can be matched like this:
72;;;
73;;; (match f
24b611e8 74;;; (($ $fun free
8320f504
AW
75;;; ($ $cont kfun
76;;; ($ $kfun src meta self ($ $cont ktail ($ $ktail))
90dce16d 77;;; ($ $kclause arity
24b611e8 78;;; ($ $cont kbody ($ $kargs names syms body))
90dce16d 79;;; alternate))))
80b01fd0
AW
80;;; #t))
81;;;
8320f504 82;;; A $continue to ktail is in tail position. $kfun, $kclause,
80b01fd0
AW
83;;; and $ktail will never be seen elsewhere in a CPS term.
84;;;
85;;; - $prompt continues to the body of the prompt, having pushed on a
86;;; prompt whose handler will continue at its "handler"
87;;; continuation. The continuation of the prompt is responsible for
7ab76a83 88;;; popping the prompt.
80b01fd0
AW
89;;;
90;;; In summary:
91;;;
92;;; - $letk, $letrec, and $continue are terms.
93;;;
94;;; - $cont is a continuation, containing a continuation body ($kargs,
59258f7c 95;;; $ktail, etc).
80b01fd0
AW
96;;;
97;;; - $continue terms contain an expression ($call, $const, $fun,
98;;; etc).
99;;;
100;;; See (language tree-il compile-cps) for details on how Tree-IL
101;;; converts to CPS.
102;;;
103;;; Code:
104
105(define-module (language cps)
106 #:use-module (ice-9 match)
107 #:use-module ((srfi srfi-1) #:select (fold))
108 #:use-module (srfi srfi-9)
109 #:use-module (srfi srfi-9 gnu)
828ed944 110 #:use-module (srfi srfi-11)
80b01fd0
AW
111 #:export (;; Helper.
112 $arity
113 make-$arity
114
115 ;; Terms.
116 $letk $continue $letrec
117
118 ;; Continuations.
119 $cont
120
121 ;; Continuation bodies.
59258f7c 122 $kreceive $kargs $kfun $ktail $kclause
80b01fd0
AW
123
124 ;; Expressions.
a9ec16f9 125 $const $prim $fun $closure $branch
cf8bb037
AW
126 $call $callk $primcall $values $prompt
127
128 ;; First-order CPS root.
129 $program
80b01fd0 130
9a1dfb7d
AW
131 ;; Fresh names.
132 label-counter var-counter
133 fresh-label fresh-var
828ed944
AW
134 with-fresh-name-state compute-max-label-and-var
135 let-fresh
9a1dfb7d 136
80b01fd0 137 ;; Building macros.
80b01fd0
AW
138 build-cps-term build-cps-cont build-cps-exp
139 rewrite-cps-term rewrite-cps-cont rewrite-cps-exp
140
141 ;; Misc.
142 parse-cps unparse-cps
405805fb
AW
143 make-global-cont-folder make-local-cont-folder
144 fold-conts fold-local-conts
2c3c086e 145 visit-cont-successors))
80b01fd0
AW
146
147;; FIXME: Use SRFI-99, when Guile adds it.
148(define-syntax define-record-type*
149 (lambda (x)
150 (define (id-append ctx . syms)
151 (datum->syntax ctx (apply symbol-append (map syntax->datum syms))))
152 (syntax-case x ()
153 ((_ name field ...)
154 (and (identifier? #'name) (and-map identifier? #'(field ...)))
155 (with-syntax ((cons (id-append #'name #'make- #'name))
156 (pred (id-append #'name #'name #'?))
157 ((getter ...) (map (lambda (f)
158 (id-append f #'name #'- f))
159 #'(field ...))))
160 #'(define-record-type name
161 (cons field ...)
162 pred
163 (field getter)
164 ...))))))
165
166(define-syntax-rule (define-cps-type name field ...)
167 (begin
168 (define-record-type* name field ...)
169 (set-record-type-printer! name print-cps)))
170
171(define (print-cps exp port)
172 (format port "#<cps ~S>" (unparse-cps exp)))
173
174;; Helper.
175(define-record-type* $arity req opt rest kw allow-other-keys?)
176
177;; Terms.
178(define-cps-type $letk conts body)
6e422a35 179(define-cps-type $continue k src exp)
cf8bb037 180(define-cps-type $letrec names syms funs body) ; Higher-order.
80b01fd0
AW
181
182;; Continuations
6e422a35 183(define-cps-type $cont k cont)
36527695 184(define-cps-type $kreceive arity k)
80b01fd0 185(define-cps-type $kargs names syms body)
8320f504 186(define-cps-type $kfun src meta self tail clause)
80b01fd0 187(define-cps-type $ktail)
90dce16d 188(define-cps-type $kclause arity cont alternate)
80b01fd0
AW
189
190;; Expressions.
80b01fd0
AW
191(define-cps-type $const val)
192(define-cps-type $prim name)
cf8bb037
AW
193(define-cps-type $fun free body) ; Higher-order.
194(define-cps-type $closure label nfree) ; First-order.
92805e21 195(define-cps-type $branch k exp)
80b01fd0 196(define-cps-type $call proc args)
cf8bb037 197(define-cps-type $callk k proc args) ; First-order.
80b01fd0
AW
198(define-cps-type $primcall name args)
199(define-cps-type $values args)
7ab76a83 200(define-cps-type $prompt escape? tag handler)
80b01fd0 201
cf8bb037
AW
202;; The root of a higher-order CPS term is $cont containing a $kfun. The
203;; root of a first-order CPS term is a $program.
204(define-cps-type $program funs)
205
9a1dfb7d
AW
206(define label-counter (make-parameter #f))
207(define var-counter (make-parameter #f))
208
209(define (fresh-label)
828ed944
AW
210 (let ((count (or (label-counter)
211 (error "fresh-label outside with-fresh-name-state"))))
9a1dfb7d
AW
212 (label-counter (1+ count))
213 count))
214
9a1dfb7d 215(define (fresh-var)
1eda52c8 216 (let ((count (or (var-counter)
828ed944 217 (error "fresh-var outside with-fresh-name-state"))))
1eda52c8 218 (var-counter (1+ count))
9a1dfb7d
AW
219 count))
220
221(define-syntax-rule (let-fresh (label ...) (var ...) body ...)
222 (let ((label (fresh-label)) ...
223 (var (fresh-var)) ...)
224 body ...))
225
828ed944 226(define-syntax-rule (with-fresh-name-state fun body ...)
d3dbf75a 227 (call-with-values (lambda () (compute-max-label-and-var fun))
3e1b97c1
AW
228 (lambda (max-label max-var)
229 (parameterize ((label-counter (1+ max-label))
230 (var-counter (1+ max-var)))
231 body ...))))
80b01fd0
AW
232
233(define-syntax build-arity
234 (syntax-rules (unquote)
235 ((_ (unquote exp)) exp)
236 ((_ (req opt rest kw allow-other-keys?))
237 (make-$arity req opt rest kw allow-other-keys?))))
238
239(define-syntax build-cont-body
59258f7c 240 (syntax-rules (unquote $kreceive $kargs $kfun $ktail $kclause)
80b01fd0
AW
241 ((_ (unquote exp))
242 exp)
36527695
AW
243 ((_ ($kreceive req rest kargs))
244 (make-$kreceive (make-$arity req '() rest '() #f) kargs))
f5fcd7f2
AW
245 ((_ ($kargs (name ...) (unquote syms) body))
246 (make-$kargs (list name ...) syms (build-cps-term body)))
80b01fd0
AW
247 ((_ ($kargs (name ...) (sym ...) body))
248 (make-$kargs (list name ...) (list sym ...) (build-cps-term body)))
249 ((_ ($kargs names syms body))
250 (make-$kargs names syms (build-cps-term body)))
8320f504
AW
251 ((_ ($kfun src meta self tail clause))
252 (make-$kfun src meta self (build-cps-cont tail) (build-cps-cont clause)))
80b01fd0
AW
253 ((_ ($ktail))
254 (make-$ktail))
90dce16d
AW
255 ((_ ($kclause arity cont alternate))
256 (make-$kclause (build-arity arity) (build-cps-cont cont)
257 (build-cps-cont alternate)))))
80b01fd0
AW
258
259(define-syntax build-cps-cont
260 (syntax-rules (unquote)
261 ((_ (unquote exp)) exp)
6e422a35 262 ((_ (k cont)) (make-$cont k (build-cont-body cont)))))
80b01fd0
AW
263
264(define-syntax build-cps-exp
265 (syntax-rules (unquote
a9ec16f9 266 $const $prim $fun $closure $branch
cf8bb037 267 $call $callk $primcall $values $prompt)
80b01fd0 268 ((_ (unquote exp)) exp)
80b01fd0
AW
269 ((_ ($const val)) (make-$const val))
270 ((_ ($prim name)) (make-$prim name))
cf8bb037
AW
271 ((_ ($fun free body)) (make-$fun free (build-cps-cont body)))
272 ((_ ($closure k nfree)) (make-$closure k nfree))
f5fcd7f2 273 ((_ ($call proc (unquote args))) (make-$call proc args))
80b01fd0
AW
274 ((_ ($call proc (arg ...))) (make-$call proc (list arg ...)))
275 ((_ ($call proc args)) (make-$call proc args))
f5fcd7f2 276 ((_ ($callk k proc (unquote args))) (make-$callk k proc args))
b3ae2b50
AW
277 ((_ ($callk k proc (arg ...))) (make-$callk k proc (list arg ...)))
278 ((_ ($callk k proc args)) (make-$callk k proc args))
f5fcd7f2 279 ((_ ($primcall name (unquote args))) (make-$primcall name args))
80b01fd0
AW
280 ((_ ($primcall name (arg ...))) (make-$primcall name (list arg ...)))
281 ((_ ($primcall name args)) (make-$primcall name args))
f5fcd7f2 282 ((_ ($values (unquote args))) (make-$values args))
80b01fd0
AW
283 ((_ ($values (arg ...))) (make-$values (list arg ...)))
284 ((_ ($values args)) (make-$values args))
92805e21 285 ((_ ($branch k exp)) (make-$branch k (build-cps-exp exp)))
7ab76a83
AW
286 ((_ ($prompt escape? tag handler))
287 (make-$prompt escape? tag handler))))
80b01fd0
AW
288
289(define-syntax build-cps-term
cf8bb037 290 (syntax-rules (unquote $letk $letk* $letconst $letrec $program $continue)
80b01fd0
AW
291 ((_ (unquote exp))
292 exp)
293 ((_ ($letk (unquote conts) body))
294 (make-$letk conts (build-cps-term body)))
295 ((_ ($letk (cont ...) body))
296 (make-$letk (list (build-cps-cont cont) ...)
297 (build-cps-term body)))
298 ((_ ($letk* () body))
299 (build-cps-term body))
300 ((_ ($letk* (cont conts ...) body))
301 (build-cps-term ($letk (cont) ($letk* (conts ...) body))))
302 ((_ ($letconst () body))
303 (build-cps-term body))
304 ((_ ($letconst ((name sym val) tail ...) body))
9a1dfb7d 305 (let-fresh (kconst) ()
80b01fd0 306 (build-cps-term
6e422a35
AW
307 ($letk ((kconst ($kargs (name) (sym) ($letconst (tail ...) body))))
308 ($continue kconst (let ((props (source-properties val)))
309 (and (pair? props) props))
310 ($const val))))))
80b01fd0
AW
311 ((_ ($letrec names gensyms funs body))
312 (make-$letrec names gensyms funs (build-cps-term body)))
cf8bb037
AW
313 ((_ ($program (unquote conts)))
314 (make-$program conts))
315 ((_ ($program (cont ...)))
316 (make-$program (list (build-cps-cont cont) ...)))
317 ((_ ($program conts))
318 (make-$program conts))
6e422a35
AW
319 ((_ ($continue k src exp))
320 (make-$continue k src (build-cps-exp exp)))))
80b01fd0
AW
321
322(define-syntax-rule (rewrite-cps-term x (pat body) ...)
323 (match x
324 (pat (build-cps-term body)) ...))
325(define-syntax-rule (rewrite-cps-cont x (pat body) ...)
326 (match x
327 (pat (build-cps-cont body)) ...))
328(define-syntax-rule (rewrite-cps-exp x (pat body) ...)
329 (match x
330 (pat (build-cps-exp body)) ...))
331
332(define (parse-cps exp)
333 (define (src exp)
334 (let ((props (source-properties exp)))
335 (and (pair? props) props)))
336 (match exp
337 ;; Continuations.
338 (('letconst k (name sym c) body)
339 (build-cps-term
6e422a35
AW
340 ($letk ((k ($kargs (name) (sym)
341 ,(parse-cps body))))
342 ($continue k (src exp) ($const c)))))
80b01fd0
AW
343 (('let k (name sym val) body)
344 (build-cps-term
6e422a35
AW
345 ($letk ((k ($kargs (name) (sym)
346 ,(parse-cps body))))
80b01fd0
AW
347 ,(parse-cps val))))
348 (('letk (cont ...) body)
349 (build-cps-term
350 ($letk ,(map parse-cps cont) ,(parse-cps body))))
351 (('k sym body)
352 (build-cps-cont
6e422a35 353 (sym ,(parse-cps body))))
36527695
AW
354 (('kreceive req rest k)
355 (build-cont-body ($kreceive req rest k)))
80b01fd0
AW
356 (('kargs names syms body)
357 (build-cont-body ($kargs names syms ,(parse-cps body))))
8320f504 358 (('kfun src meta self tail clause)
80b01fd0 359 (build-cont-body
8320f504 360 ($kfun (src exp) meta self ,(parse-cps tail)
24b611e8 361 ,(and=> clause parse-cps))))
80b01fd0
AW
362 (('ktail)
363 (build-cont-body
364 ($ktail)))
365 (('kclause (req opt rest kw allow-other-keys?) body)
366 (build-cont-body
367 ($kclause (req opt rest kw allow-other-keys?)
90dce16d
AW
368 ,(parse-cps body)
369 ,#f)))
370 (('kclause (req opt rest kw allow-other-keys?) body alternate)
371 (build-cont-body
372 ($kclause (req opt rest kw allow-other-keys?)
373 ,(parse-cps body)
374 ,(parse-cps alternate))))
80b01fd0
AW
375 (('kseq body)
376 (build-cont-body ($kargs () () ,(parse-cps body))))
377
378 ;; Calls.
379 (('continue k exp)
6e422a35 380 (build-cps-term ($continue k (src exp) ,(parse-cps exp))))
80b01fd0
AW
381 (('const exp)
382 (build-cps-exp ($const exp)))
383 (('prim name)
384 (build-cps-exp ($prim name)))
24b611e8
AW
385 (('fun free body)
386 (build-cps-exp ($fun free ,(parse-cps body))))
cf8bb037
AW
387 (('closure k nfree)
388 (build-cps-exp ($closure k nfree)))
80b01fd0
AW
389 (('letrec ((name sym fun) ...) body)
390 (build-cps-term
391 ($letrec name sym (map parse-cps fun) ,(parse-cps body))))
cf8bb037
AW
392 (('program (cont ...))
393 (build-cps-term ($program ,(map parse-cps cont))))
80b01fd0
AW
394 (('call proc arg ...)
395 (build-cps-exp ($call proc arg)))
b3ae2b50
AW
396 (('callk k proc arg ...)
397 (build-cps-exp ($callk k proc arg)))
80b01fd0
AW
398 (('primcall name arg ...)
399 (build-cps-exp ($primcall name arg)))
92805e21
AW
400 (('branch k exp)
401 (build-cps-exp ($branch k ,(parse-cps exp))))
80b01fd0
AW
402 (('values arg ...)
403 (build-cps-exp ($values arg)))
7ab76a83
AW
404 (('prompt escape? tag handler)
405 (build-cps-exp ($prompt escape? tag handler)))
80b01fd0
AW
406 (_
407 (error "unexpected cps" exp))))
408
409(define (unparse-cps exp)
410 (match exp
411 ;; Continuations.
6e422a35
AW
412 (($ $letk (($ $cont k ($ $kargs (name) (sym) body)))
413 ($ $continue k src ($ $const c)))
80b01fd0
AW
414 `(letconst ,k (,name ,sym ,c)
415 ,(unparse-cps body)))
6e422a35 416 (($ $letk (($ $cont k ($ $kargs (name) (sym) body))) val)
80b01fd0
AW
417 `(let ,k (,name ,sym ,(unparse-cps val))
418 ,(unparse-cps body)))
419 (($ $letk conts body)
420 `(letk ,(map unparse-cps conts) ,(unparse-cps body)))
6e422a35 421 (($ $cont sym body)
80b01fd0 422 `(k ,sym ,(unparse-cps body)))
36527695
AW
423 (($ $kreceive ($ $arity req () rest '() #f) k)
424 `(kreceive ,req ,rest ,k))
80b01fd0
AW
425 (($ $kargs () () body)
426 `(kseq ,(unparse-cps body)))
427 (($ $kargs names syms body)
428 `(kargs ,names ,syms ,(unparse-cps body)))
8320f504
AW
429 (($ $kfun src meta self tail clause)
430 `(kfun ,meta ,self ,(unparse-cps tail) ,(unparse-cps clause)))
80b01fd0
AW
431 (($ $ktail)
432 `(ktail))
90dce16d
AW
433 (($ $kclause ($ $arity req opt rest kw allow-other-keys?) body alternate)
434 `(kclause (,req ,opt ,rest ,kw ,allow-other-keys?) ,(unparse-cps body)
435 . ,(if alternate (list (unparse-cps alternate)) '())))
80b01fd0
AW
436
437 ;; Calls.
6e422a35 438 (($ $continue k src exp)
80b01fd0 439 `(continue ,k ,(unparse-cps exp)))
80b01fd0
AW
440 (($ $const val)
441 `(const ,val))
442 (($ $prim name)
443 `(prim ,name))
24b611e8
AW
444 (($ $fun free body)
445 `(fun ,free ,(unparse-cps body)))
cf8bb037
AW
446 (($ $closure k nfree)
447 `(closure ,k ,nfree))
80b01fd0
AW
448 (($ $letrec names syms funs body)
449 `(letrec ,(map (lambda (name sym fun)
450 (list name sym (unparse-cps fun)))
451 names syms funs)
452 ,(unparse-cps body)))
cf8bb037
AW
453 (($ $program conts)
454 `(program ,(map unparse-cps conts)))
80b01fd0
AW
455 (($ $call proc args)
456 `(call ,proc ,@args))
b3ae2b50
AW
457 (($ $callk k proc args)
458 `(callk ,k ,proc ,@args))
80b01fd0
AW
459 (($ $primcall name args)
460 `(primcall ,name ,@args))
92805e21
AW
461 (($ $branch k exp)
462 `(branch ,k ,(unparse-cps exp)))
80b01fd0
AW
463 (($ $values args)
464 `(values ,@args))
7ab76a83
AW
465 (($ $prompt escape? tag handler)
466 `(prompt ,escape? ,tag ,handler))
80b01fd0
AW
467 (_
468 (error "unexpected cps" exp))))
469
405805fb 470(define-syntax-rule (make-global-cont-folder seed ...)
686a6490 471 (lambda (proc cont seed ...)
828ed944
AW
472 (define (cont-folder cont seed ...)
473 (match cont
474 (($ $cont k cont)
475 (let-values (((seed ...) (proc k cont seed ...)))
476 (match cont
477 (($ $kargs names syms body)
478 (term-folder body seed ...))
479
8320f504 480 (($ $kfun src meta self tail clause)
828ed944 481 (let-values (((seed ...) (cont-folder tail seed ...)))
90dce16d
AW
482 (if clause
483 (cont-folder clause seed ...)
484 (values seed ...))))
485
486 (($ $kclause arity body alternate)
487 (let-values (((seed ...) (cont-folder body seed ...)))
488 (if alternate
489 (cont-folder alternate seed ...)
490 (values seed ...))))
828ed944
AW
491
492 (_ (values seed ...)))))))
493
494 (define (fun-folder fun seed ...)
495 (match fun
24b611e8 496 (($ $fun free body)
828ed944
AW
497 (cont-folder body seed ...))))
498
499 (define (term-folder term seed ...)
500 (match term
501 (($ $letk conts body)
502 (let-values (((seed ...) (term-folder body seed ...)))
2ad91e6b
AW
503 (let lp ((conts conts) (seed seed) ...)
504 (if (null? conts)
505 (values seed ...)
506 (let-values (((seed ...) (cont-folder (car conts) seed ...)))
507 (lp (cdr conts) seed ...))))))
828ed944
AW
508
509 (($ $continue k src exp)
510 (match exp
405805fb 511 (($ $fun) (fun-folder exp seed ...))
828ed944
AW
512 (_ (values seed ...))))
513
514 (($ $letrec names syms funs body)
515 (let-values (((seed ...) (term-folder body seed ...)))
2ad91e6b
AW
516 (let lp ((funs funs) (seed seed) ...)
517 (if (null? funs)
518 (values seed ...)
519 (let-values (((seed ...) (fun-folder (car funs) seed ...)))
520 (lp (cdr funs) seed ...))))))))
828ed944 521
686a6490 522 (cont-folder cont seed ...)))
828ed944 523
405805fb
AW
524(define-syntax-rule (make-local-cont-folder seed ...)
525 (lambda (proc cont seed ...)
526 (define (cont-folder cont seed ...)
527 (match cont
528 (($ $cont k (and cont ($ $kargs names syms body)))
529 (let-values (((seed ...) (proc k cont seed ...)))
530 (term-folder body seed ...)))
531 (($ $cont k cont)
532 (proc k cont seed ...))))
533 (define (term-folder term seed ...)
534 (match term
535 (($ $letk conts body)
536 (let-values (((seed ...) (term-folder body seed ...)))
537 (let lp ((conts conts) (seed seed) ...)
538 (match conts
539 (() (values seed ...))
540 ((cont) (cont-folder cont seed ...))
541 ((cont . conts)
542 (let-values (((seed ...) (cont-folder cont seed ...)))
543 (lp conts seed ...)))))))
544 (($ $letrec names syms funs body) (term-folder body seed ...))
545 (_ (values seed ...))))
546 (define (clause-folder clause seed ...)
547 (match clause
548 (($ $cont k (and cont ($ $kclause arity body alternate)))
549 (let-values (((seed ...) (proc k cont seed ...)))
550 (if alternate
551 (let-values (((seed ...) (cont-folder body seed ...)))
552 (clause-folder alternate seed ...))
553 (cont-folder body seed ...))))))
554 (match cont
555 (($ $cont k (and cont ($ $kfun src meta self tail clause)))
556 (let*-values (((seed ...) (proc k cont seed ...))
557 ((seed ...) (if clause
558 (clause-folder clause seed ...)
559 (values seed ...))))
560 (cont-folder tail seed ...))))))
561
828ed944 562(define (compute-max-label-and-var fun)
cf8bb037
AW
563 (match fun
564 (($ $cont)
565 ((make-global-cont-folder max-label max-var)
566 (lambda (label cont max-label max-var)
567 (values (max label max-label)
568 (match cont
569 (($ $kargs names vars body)
570 (let lp ((body body) (max-var (fold max max-var vars)))
571 (match body
572 (($ $letk conts body) (lp body max-var))
573 (($ $letrec names vars funs body)
574 (lp body (fold max max-var vars)))
575 (_ max-var))))
576 (($ $kfun src meta self)
577 (max self max-var))
578 (_ max-var))))
579 fun -1 -1))
580 (($ $program conts)
581 (define (fold/2 proc in s0 s1)
582 (if (null? in)
583 (values s0 s1)
584 (let-values (((s0 s1) (proc (car in) s0 s1)))
585 (fold/2 proc (cdr in) s0 s1))))
586 (let lp ((conts conts) (max-label -1) (max-var -1))
587 (if (null? conts)
588 (values max-label max-var)
589 (call-with-values (lambda ()
590 ((make-local-cont-folder max-label max-var)
591 (lambda (label cont max-label max-var)
592 (values (max label max-label)
593 (match cont
594 (($ $kargs names vars body)
595 (fold max max-var vars))
596 (($ $kfun src meta self)
597 (max self max-var))
598 (_ max-var))))
599 (car conts) max-label max-var))
600 (lambda (max-label max-var)
601 (lp (cdr conts) max-label max-var))))))))
80b01fd0 602
828ed944 603(define (fold-conts proc seed fun)
405805fb 604 ((make-global-cont-folder seed) proc fun seed))
80b01fd0 605
a6f823bd 606(define (fold-local-conts proc seed fun)
405805fb 607 ((make-local-cont-folder seed) proc fun seed))
2c3c086e
AW
608
609(define (visit-cont-successors proc cont)
610 (match cont
611 (($ $kargs names syms body)
612 (let lp ((body body))
613 (match body
614 (($ $letk conts body) (lp body))
615 (($ $letrec names vars funs body) (lp body))
616 (($ $continue k src exp)
617 (match exp
618 (($ $prompt escape? tag handler) (proc k handler))
92805e21 619 (($ $branch kt) (proc k kt))
2c3c086e
AW
620 (_ (proc k)))))))
621
2c3c086e
AW
622 (($ $kreceive arity k) (proc k))
623
624 (($ $kclause arity ($ $cont kbody) #f) (proc kbody))
625
626 (($ $kclause arity ($ $cont kbody) ($ $cont kalt)) (proc kbody kalt))
627
8320f504 628 (($ $kfun src meta self tail ($ $cont clause)) (proc clause))
2c3c086e 629
8320f504 630 (($ $kfun src meta self tail #f) (proc))
2c3c086e
AW
631
632 (($ $ktail) (proc))))