Don't include libunistring headers in Guile public headers
[bpt/guile.git] / module / language / tree-il / fix-letrec.scm
CommitLineData
c21c89b1
AW
1;;; transformation of letrec into simpler forms
2
3;; Copyright (C) 2009 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(define-module (language tree-il fix-letrec)
20 #:use-module (system base syntax)
80af1168
AW
21 #:use-module (srfi srfi-1)
22 #:use-module (srfi srfi-11)
c21c89b1 23 #:use-module (language tree-il)
80af1168 24 #:use-module (language tree-il primitives)
c21c89b1
AW
25 #:export (fix-letrec!))
26
27;; For a detailed discussion, see "Fixing Letrec: A Faithful Yet
28;; Efficient Implementation of Scheme’s Recursive Binding Construct", by
29;; Oscar Waddell, Dipanwita Sarkar, and R. Kent Dybvig.
30
80af1168
AW
31(define fix-fold
32 (make-tree-il-folder unref ref set simple lambda complex))
33
34(define (simple-expression? x bound-vars)
35 (record-case x
36 ((<void>) #t)
37 ((<const>) #t)
38 ((<lexical-ref> gensym)
39 (not (memq gensym bound-vars)))
40 ((<conditional> test then else)
41 (and (simple-expression? test bound-vars)
42 (simple-expression? then bound-vars)
43 (simple-expression? else bound-vars)))
44 ((<sequence> exps)
45 (and-map (lambda (x) (simple-expression? x bound-vars))
46 exps))
47 ((<application> proc args)
48 (and (primitive-ref? proc)
49 (effect-free-primitive? (primitive-ref-name proc))
50 (and-map (lambda (x) (simple-expression? x bound-vars))
51 args)))
52 (else #f)))
53
54(define (partition-vars x)
55 (let-values
56 (((unref ref set simple lambda* complex)
57 (fix-fold x
58 (lambda (x unref ref set simple lambda* complex)
59 (record-case x
60 ((<lexical-ref> gensym)
61 (values (delq gensym unref)
62 (lset-adjoin eq? ref gensym)
63 set
64 simple
65 lambda*
66 complex))
67 ((<lexical-set> gensym)
68 (values unref
69 ref
70 (lset-adjoin eq? set gensym)
71 simple
72 lambda*
73 complex))
74 ((<letrec> vars)
75 (values (append vars unref)
76 ref
77 set
78 simple
79 lambda*
80 complex))
81 (else
82 (values unref ref set simple lambda* complex))))
83 (lambda (x unref ref set simple lambda* complex)
84 (record-case x
85 ((<letrec> (orig-vars vars) vals)
86 (let lp ((vars orig-vars) (vals vals)
87 (s '()) (l '()) (c '()))
88 (cond
89 ((null? vars)
90 (values unref
91 ref
92 set
93 (append s simple)
94 (append l lambda*)
95 (append c complex)))
96 ((memq (car vars) unref)
97 (lp (cdr vars) (cdr vals)
98 s l c))
99 ((memq (car vars) set)
100 (lp (cdr vars) (cdr vals)
101 s l (cons (car vars) c)))
102 ((lambda? (car vals))
103 (lp (cdr vars) (cdr vals)
104 s (cons (car vars) l) c))
105 ((simple-expression? (car vals) orig-vars)
106 (lp (cdr vars) (cdr vals)
107 (cons (car vars) s) l c))
108 (else
109 (lp (cdr vars) (cdr vals)
110 s l (cons (car vars) c))))))
111 (else
112 (values unref ref set simple lambda* complex))))
113 '()
114 '()
115 '()
116 '()
117 '()
118 '())))
119 (values unref simple lambda* complex)))
120
c21c89b1 121(define (fix-letrec! x)
80af1168
AW
122 (let-values (((unref simple lambda* complex) (partition-vars x)))
123 (post-order!
124 (lambda (x)
125 (record-case x
126
127 ;; Sets to unreferenced variables may be replaced by their
128 ;; expression, called for effect.
129 ((<lexical-set> gensym exp)
130 (if (memq gensym unref)
131 (make-sequence #f (list (make-void #f) exp))
132 x))
133
134 ((<letrec> src names vars vals body)
135 (let ((binds (map list vars names vals)))
136 (define (lookup set)
137 (map (lambda (v) (assq v binds))
138 (lset-intersection eq? vars set)))
139 (let ((u (lookup unref))
140 (s (lookup simple))
141 (l (lookup lambda*))
142 (c (lookup complex)))
143 ;; Bind "simple" bindings, and locations for complex
144 ;; bindings.
145 (make-let
146 src
147 (append (map cadr s) (map cadr c))
148 (append (map car s) (map car c))
149 (append (map caddr s) (map (lambda (x) (make-void #f)) c))
150 ;; Bind lambdas using the fixpoint operator.
151 (make-fix
152 src (map cadr l) (map car l) (map caddr l)
153 (make-sequence
154 src
155 (append
156 ;; The right-hand-sides of the unreferenced
157 ;; bindings, for effect.
158 (map caddr u)
159 (if (null? c)
160 ;; No complex bindings, just emit the body.
161 (list body)
162 (list
163 ;; Evaluate the the "complex" bindings, in a `let' to
164 ;; indicate that order doesn't matter, and bind to
165 ;; their variables.
166 (let ((tmps (map (lambda (x) (gensym)) c)))
167 (make-let
168 #f (map cadr c) tmps (map caddr c)
169 (make-sequence
170 #f
171 (map (lambda (x tmp)
172 (make-lexical-set
173 #f (cadr x) (car x)
174 (make-lexical-ref #f (cadr x) tmp)))
175 c tmps))))
176 ;; Finally, the body.
177 body)))))))))
178
179 (else x)))
180 x)))