Merge commit '5cfeff11cc58148c58a85a879fd7a3e7cfbbe8e2'
[bpt/guile.git] / module / language / cps.scm
CommitLineData
80b01fd0
AW
1;;; Continuation-passing style (CPS) intermediate language (IL)
2
7ab76a83 3;; Copyright (C) 2013, 2014 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:
30;;; $kif for test continuations, $kargs for continuations that bind
31;;; values, 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;;;
60;;; - $kentry labels an entry point for a $fun (a function), and
61;;; contains a $ktail representing the formal argument which is the
62;;; function's continuation.
63;;;
64;;; - $kentry also contains $kclause continuations, corresponding to
65;;; the case-lambda clauses of the function. $kclause actually
66;;; contains the clause body. This is because the $kclause
67;;; logically matches or doesn't match a given set of actual
68;;; arguments against a formal arity, then proceeds to a "body"
69;;; continuation (which is a $kargs).
70;;;
71;;; That's to say that a $fun can be matched like this:
72;;;
73;;; (match f
6e422a35
AW
74;;; (($ $fun src meta free
75;;; ($ $cont kentry
80b01fd0
AW
76;;; ($ $kentry self ($ $cont ktail _ ($ $ktail))
77;;; (($ $kclause arity
78;;; ($ $cont kbody _ ($ $kargs names syms body)))
79;;; ...))))
80;;; #t))
81;;;
82;;; A $continue to ktail is in tail position. $kentry, $kclause,
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,
95;;; $kif, etc).
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)
110 #:export (;; Helper.
111 $arity
112 make-$arity
113
114 ;; Terms.
115 $letk $continue $letrec
116
117 ;; Continuations.
118 $cont
119
120 ;; Continuation bodies.
36527695 121 $kif $kreceive $kargs $kentry $ktail $kclause
80b01fd0
AW
122
123 ;; Expressions.
b3ae2b50 124 $void $const $prim $fun $call $callk $primcall $values $prompt
80b01fd0
AW
125
126 ;; Building macros.
127 let-gensyms
128 build-cps-term build-cps-cont build-cps-exp
129 rewrite-cps-term rewrite-cps-cont rewrite-cps-exp
130
131 ;; Misc.
132 parse-cps unparse-cps
133 fold-conts fold-local-conts))
134
135;; FIXME: Use SRFI-99, when Guile adds it.
136(define-syntax define-record-type*
137 (lambda (x)
138 (define (id-append ctx . syms)
139 (datum->syntax ctx (apply symbol-append (map syntax->datum syms))))
140 (syntax-case x ()
141 ((_ name field ...)
142 (and (identifier? #'name) (and-map identifier? #'(field ...)))
143 (with-syntax ((cons (id-append #'name #'make- #'name))
144 (pred (id-append #'name #'name #'?))
145 ((getter ...) (map (lambda (f)
146 (id-append f #'name #'- f))
147 #'(field ...))))
148 #'(define-record-type name
149 (cons field ...)
150 pred
151 (field getter)
152 ...))))))
153
154(define-syntax-rule (define-cps-type name field ...)
155 (begin
156 (define-record-type* name field ...)
157 (set-record-type-printer! name print-cps)))
158
159(define (print-cps exp port)
160 (format port "#<cps ~S>" (unparse-cps exp)))
161
162;; Helper.
163(define-record-type* $arity req opt rest kw allow-other-keys?)
164
165;; Terms.
166(define-cps-type $letk conts body)
6e422a35 167(define-cps-type $continue k src exp)
80b01fd0
AW
168(define-cps-type $letrec names syms funs body)
169
170;; Continuations
6e422a35 171(define-cps-type $cont k cont)
80b01fd0 172(define-cps-type $kif kt kf)
36527695 173(define-cps-type $kreceive arity k)
80b01fd0
AW
174(define-cps-type $kargs names syms body)
175(define-cps-type $kentry self tail clauses)
176(define-cps-type $ktail)
177(define-cps-type $kclause arity cont)
178
179;; Expressions.
80b01fd0
AW
180(define-cps-type $void)
181(define-cps-type $const val)
182(define-cps-type $prim name)
6e422a35 183(define-cps-type $fun src meta free body)
80b01fd0 184(define-cps-type $call proc args)
b3ae2b50 185(define-cps-type $callk k proc args)
80b01fd0
AW
186(define-cps-type $primcall name args)
187(define-cps-type $values args)
7ab76a83 188(define-cps-type $prompt escape? tag handler)
80b01fd0
AW
189
190(define-syntax let-gensyms
191 (syntax-rules ()
192 ((_ (sym ...) body body* ...)
193 (let ((sym (gensym (symbol->string 'sym))) ...)
194 body body* ...))))
195
196(define-syntax build-arity
197 (syntax-rules (unquote)
198 ((_ (unquote exp)) exp)
199 ((_ (req opt rest kw allow-other-keys?))
200 (make-$arity req opt rest kw allow-other-keys?))))
201
202(define-syntax build-cont-body
36527695 203 (syntax-rules (unquote $kif $kreceive $kargs $kentry $ktail $kclause)
80b01fd0
AW
204 ((_ (unquote exp))
205 exp)
206 ((_ ($kif kt kf))
207 (make-$kif kt kf))
36527695
AW
208 ((_ ($kreceive req rest kargs))
209 (make-$kreceive (make-$arity req '() rest '() #f) kargs))
80b01fd0
AW
210 ((_ ($kargs (name ...) (sym ...) body))
211 (make-$kargs (list name ...) (list sym ...) (build-cps-term body)))
212 ((_ ($kargs names syms body))
213 (make-$kargs names syms (build-cps-term body)))
214 ((_ ($kentry self tail (unquote clauses)))
215 (make-$kentry self (build-cps-cont tail) clauses))
216 ((_ ($kentry self tail (clause ...)))
217 (make-$kentry self (build-cps-cont tail) (list (build-cps-cont clause) ...)))
218 ((_ ($ktail))
219 (make-$ktail))
220 ((_ ($kclause arity cont))
221 (make-$kclause (build-arity arity) (build-cps-cont cont)))))
222
223(define-syntax build-cps-cont
224 (syntax-rules (unquote)
225 ((_ (unquote exp)) exp)
6e422a35 226 ((_ (k cont)) (make-$cont k (build-cont-body cont)))))
80b01fd0
AW
227
228(define-syntax build-cps-exp
229 (syntax-rules (unquote
b3ae2b50 230 $void $const $prim $fun $call $callk $primcall $values $prompt)
80b01fd0 231 ((_ (unquote exp)) exp)
80b01fd0
AW
232 ((_ ($void)) (make-$void))
233 ((_ ($const val)) (make-$const val))
234 ((_ ($prim name)) (make-$prim name))
6e422a35
AW
235 ((_ ($fun src meta free body))
236 (make-$fun src meta free (build-cps-cont body)))
80b01fd0
AW
237 ((_ ($call proc (arg ...))) (make-$call proc (list arg ...)))
238 ((_ ($call proc args)) (make-$call proc args))
b3ae2b50
AW
239 ((_ ($callk k proc (arg ...))) (make-$callk k proc (list arg ...)))
240 ((_ ($callk k proc args)) (make-$callk k proc args))
80b01fd0
AW
241 ((_ ($primcall name (arg ...))) (make-$primcall name (list arg ...)))
242 ((_ ($primcall name args)) (make-$primcall name args))
243 ((_ ($values (arg ...))) (make-$values (list arg ...)))
244 ((_ ($values args)) (make-$values args))
7ab76a83
AW
245 ((_ ($prompt escape? tag handler))
246 (make-$prompt escape? tag handler))))
80b01fd0
AW
247
248(define-syntax build-cps-term
249 (syntax-rules (unquote $letk $letk* $letconst $letrec $continue)
250 ((_ (unquote exp))
251 exp)
252 ((_ ($letk (unquote conts) body))
253 (make-$letk conts (build-cps-term body)))
254 ((_ ($letk (cont ...) body))
255 (make-$letk (list (build-cps-cont cont) ...)
256 (build-cps-term body)))
257 ((_ ($letk* () body))
258 (build-cps-term body))
259 ((_ ($letk* (cont conts ...) body))
260 (build-cps-term ($letk (cont) ($letk* (conts ...) body))))
261 ((_ ($letconst () body))
262 (build-cps-term body))
263 ((_ ($letconst ((name sym val) tail ...) body))
264 (let-gensyms (kconst)
265 (build-cps-term
6e422a35
AW
266 ($letk ((kconst ($kargs (name) (sym) ($letconst (tail ...) body))))
267 ($continue kconst (let ((props (source-properties val)))
268 (and (pair? props) props))
269 ($const val))))))
80b01fd0
AW
270 ((_ ($letrec names gensyms funs body))
271 (make-$letrec names gensyms funs (build-cps-term body)))
6e422a35
AW
272 ((_ ($continue k src exp))
273 (make-$continue k src (build-cps-exp exp)))))
80b01fd0
AW
274
275(define-syntax-rule (rewrite-cps-term x (pat body) ...)
276 (match x
277 (pat (build-cps-term body)) ...))
278(define-syntax-rule (rewrite-cps-cont x (pat body) ...)
279 (match x
280 (pat (build-cps-cont body)) ...))
281(define-syntax-rule (rewrite-cps-exp x (pat body) ...)
282 (match x
283 (pat (build-cps-exp body)) ...))
284
285(define (parse-cps exp)
286 (define (src exp)
287 (let ((props (source-properties exp)))
288 (and (pair? props) props)))
289 (match exp
290 ;; Continuations.
291 (('letconst k (name sym c) body)
292 (build-cps-term
6e422a35
AW
293 ($letk ((k ($kargs (name) (sym)
294 ,(parse-cps body))))
295 ($continue k (src exp) ($const c)))))
80b01fd0
AW
296 (('let k (name sym val) body)
297 (build-cps-term
6e422a35
AW
298 ($letk ((k ($kargs (name) (sym)
299 ,(parse-cps body))))
80b01fd0
AW
300 ,(parse-cps val))))
301 (('letk (cont ...) body)
302 (build-cps-term
303 ($letk ,(map parse-cps cont) ,(parse-cps body))))
304 (('k sym body)
305 (build-cps-cont
6e422a35 306 (sym ,(parse-cps body))))
80b01fd0
AW
307 (('kif kt kf)
308 (build-cont-body ($kif kt kf)))
36527695
AW
309 (('kreceive req rest k)
310 (build-cont-body ($kreceive req rest k)))
80b01fd0
AW
311 (('kargs names syms body)
312 (build-cont-body ($kargs names syms ,(parse-cps body))))
313 (('kentry self tail clauses)
314 (build-cont-body
315 ($kentry self ,(parse-cps tail) ,(map parse-cps clauses))))
316 (('ktail)
317 (build-cont-body
318 ($ktail)))
319 (('kclause (req opt rest kw allow-other-keys?) body)
320 (build-cont-body
321 ($kclause (req opt rest kw allow-other-keys?)
322 ,(parse-cps body))))
323 (('kseq body)
324 (build-cont-body ($kargs () () ,(parse-cps body))))
325
326 ;; Calls.
327 (('continue k exp)
6e422a35 328 (build-cps-term ($continue k (src exp) ,(parse-cps exp))))
80b01fd0
AW
329 (('void)
330 (build-cps-exp ($void)))
331 (('const exp)
332 (build-cps-exp ($const exp)))
333 (('prim name)
334 (build-cps-exp ($prim name)))
335 (('fun meta free body)
6e422a35 336 (build-cps-exp ($fun (src exp) meta free ,(parse-cps body))))
80b01fd0
AW
337 (('letrec ((name sym fun) ...) body)
338 (build-cps-term
339 ($letrec name sym (map parse-cps fun) ,(parse-cps body))))
340 (('call proc arg ...)
341 (build-cps-exp ($call proc arg)))
b3ae2b50
AW
342 (('callk k proc arg ...)
343 (build-cps-exp ($callk k proc arg)))
80b01fd0
AW
344 (('primcall name arg ...)
345 (build-cps-exp ($primcall name arg)))
346 (('values arg ...)
347 (build-cps-exp ($values arg)))
7ab76a83
AW
348 (('prompt escape? tag handler)
349 (build-cps-exp ($prompt escape? tag handler)))
80b01fd0
AW
350 (_
351 (error "unexpected cps" exp))))
352
353(define (unparse-cps exp)
354 (match exp
355 ;; Continuations.
6e422a35
AW
356 (($ $letk (($ $cont k ($ $kargs (name) (sym) body)))
357 ($ $continue k src ($ $const c)))
80b01fd0
AW
358 `(letconst ,k (,name ,sym ,c)
359 ,(unparse-cps body)))
6e422a35 360 (($ $letk (($ $cont k ($ $kargs (name) (sym) body))) val)
80b01fd0
AW
361 `(let ,k (,name ,sym ,(unparse-cps val))
362 ,(unparse-cps body)))
363 (($ $letk conts body)
364 `(letk ,(map unparse-cps conts) ,(unparse-cps body)))
6e422a35 365 (($ $cont sym body)
80b01fd0
AW
366 `(k ,sym ,(unparse-cps body)))
367 (($ $kif kt kf)
368 `(kif ,kt ,kf))
36527695
AW
369 (($ $kreceive ($ $arity req () rest '() #f) k)
370 `(kreceive ,req ,rest ,k))
80b01fd0
AW
371 (($ $kargs () () body)
372 `(kseq ,(unparse-cps body)))
373 (($ $kargs names syms body)
374 `(kargs ,names ,syms ,(unparse-cps body)))
375 (($ $kentry self tail clauses)
376 `(kentry ,self ,(unparse-cps tail) ,(map unparse-cps clauses)))
377 (($ $ktail)
378 `(ktail))
379 (($ $kclause ($ $arity req opt rest kw allow-other-keys?) body)
380 `(kclause (,req ,opt ,rest ,kw ,allow-other-keys?) ,(unparse-cps body)))
381
382 ;; Calls.
6e422a35 383 (($ $continue k src exp)
80b01fd0 384 `(continue ,k ,(unparse-cps exp)))
80b01fd0
AW
385 (($ $void)
386 `(void))
387 (($ $const val)
388 `(const ,val))
389 (($ $prim name)
390 `(prim ,name))
6e422a35 391 (($ $fun src meta free body)
80b01fd0
AW
392 `(fun ,meta ,free ,(unparse-cps body)))
393 (($ $letrec names syms funs body)
394 `(letrec ,(map (lambda (name sym fun)
395 (list name sym (unparse-cps fun)))
396 names syms funs)
397 ,(unparse-cps body)))
398 (($ $call proc args)
399 `(call ,proc ,@args))
b3ae2b50
AW
400 (($ $callk k proc args)
401 `(callk ,k ,proc ,@args))
80b01fd0
AW
402 (($ $primcall name args)
403 `(primcall ,name ,@args))
404 (($ $values args)
405 `(values ,@args))
7ab76a83
AW
406 (($ $prompt escape? tag handler)
407 `(prompt ,escape? ,tag ,handler))
80b01fd0
AW
408 (_
409 (error "unexpected cps" exp))))
410
411(define (fold-conts proc seed fun)
412 (define (cont-folder cont seed)
413 (match cont
6e422a35
AW
414 (($ $cont k cont)
415 (let ((seed (proc k cont seed)))
80b01fd0
AW
416 (match cont
417 (($ $kargs names syms body)
418 (term-folder body seed))
419
420 (($ $kentry self tail clauses)
421 (fold cont-folder (cont-folder tail seed) clauses))
422
423 (($ $kclause arity body)
424 (cont-folder body seed))
425
426 (_ seed))))))
427
428 (define (fun-folder fun seed)
429 (match fun
6e422a35 430 (($ $fun src meta free body)
80b01fd0
AW
431 (cont-folder body seed))))
432
433 (define (term-folder term seed)
434 (match term
435 (($ $letk conts body)
436 (fold cont-folder (term-folder body seed) conts))
437
6e422a35 438 (($ $continue k src exp)
80b01fd0
AW
439 (match exp
440 (($ $fun) (fun-folder exp seed))
441 (_ seed)))
442
443 (($ $letrec names syms funs body)
444 (fold fun-folder (term-folder body seed) funs))))
445
446 (fun-folder fun seed))
447
448(define (fold-local-conts proc seed cont)
449 (define (cont-folder cont seed)
450 (match cont
6e422a35
AW
451 (($ $cont k cont)
452 (let ((seed (proc k cont seed)))
80b01fd0
AW
453 (match cont
454 (($ $kargs names syms body)
455 (term-folder body seed))
456
457 (($ $kentry self tail clauses)
458 (fold cont-folder (cont-folder tail seed) clauses))
459
460 (($ $kclause arity body)
461 (cont-folder body seed))
462
463 (_ seed))))))
464
465 (define (term-folder term seed)
466 (match term
467 (($ $letk conts body)
468 (fold cont-folder (term-folder body seed) conts))
469
470 (($ $continue) seed)
471
472 (($ $letrec names syms funs body) (term-folder body seed))))
473
474 (cont-folder cont seed))