1#lang eopl
2
3(require "cps-in-lang.rkt")
4(require "cps-out-lang.rkt")
5
6(provide cps-of-program)
7
8;; cps-of-program : InpExp -> TfExp
9;; Page: 224
10(define cps-of-program
11  (lambda (pgm)
12    (cases program pgm
13      (a-program (exp1)
14                 (cps-a-program
15                  (cps-of-exps (list exp1)
16                               (lambda (new-args)
17                                 (simple-exp->exp (car new-args)))))))))
18
19;; cps-of-exp : Exp * SimpleExp -> TfExp
20;; Page: 222, 228, 231
21(define cps-of-exp
22  (lambda (exp k-exp)
23    (cases expression exp
24      (const-exp (num) (make-send-to-cont k-exp (cps-const-exp num)))
25      (var-exp (var) (make-send-to-cont k-exp (cps-var-exp var)))
26      (proc-exp (vars body)
27                (make-send-to-cont k-exp
28                                   (cps-proc-exp (append vars (list 'k%00))
29                                                 (cps-of-exp body (cps-var-exp 'k%00)))))
30      (zero?-exp (exp1)
31                 (cps-of-zero?-exp exp1 k-exp))
32      (diff-exp (exp1 exp2)
33                (cps-of-diff-exp exp1 exp2 k-exp))
34      (sum-exp (exps)
35               (cps-of-sum-exp exps k-exp))
36      (if-exp (exp1 exp2 exp3)
37              (cps-of-if-exp exp1 exp2 exp3 k-exp))
38      (let-exp (var exp1 body)
39               (cps-of-let-exp var exp1 body k-exp))
40      (letrec-exp (ids bidss proc-bodies body)
41                  (cps-of-letrec-exp ids bidss proc-bodies body k-exp))
42      (call-exp (rator rands)
43                (cps-of-call-exp rator rands k-exp))
44
45      ;; new for cps-side-effects-lang
46      ;; Page: 228
47      (print-exp (rator)
48                 (cps-of-exps (list rator)
49                              (lambda (simples)
50                                (cps-printk-exp
51                                 (car simples)
52                                 (make-send-to-cont k-exp (cps-const-exp 38))))))
53
54      ;; Page 231
55      (newref-exp (exp1)
56                  (cps-of-exps (list exp1)
57                               (lambda (simples)
58                                 (cps-newrefk-exp (car simples) k-exp))))
59
60      (deref-exp (exp1)
61                 (cps-of-exps (list exp1)
62                              (lambda (simples)
63                                (cps-derefk-exp (car simples) k-exp))))
64
65      (setref-exp (exp1 exp2)
66                  (cps-of-exps (list exp1 exp2)
67                               (lambda (simples)
68                                 (cps-setrefk-exp
69                                  (car simples)
70                                  (cadr simples)
71                                  ;; the third argument will be evaluated tail-recursively.
72                                  ;; returns 23, just like in explicit-refs
73                                  (make-send-to-cont k-exp (cps-const-exp 23))))))
74
75      )))
76
77;; cps-of-exps : (list-of expression) *
78;;                      ((list-of cps-simple-expression) -> cps-expression)
79;;                      -> cps-expression
80;; Page: 219
81;; usage:
82;;   -- assume e_i's are non-simple, b_i's are simple
83;;   -- then
84;;        (cps-of-exps '(b1 b2 e1 b3 e2 e3) F) ==
85;;        [e1](\v1.[e2](\v2.[e3](\v3.(F `(,<b1> ,<b2> ,v1 ,<b3> ,v2 ,v3)))))
86;;      where <b> is cps-of-simple-exp of b.
87(define cps-of-exps
88  (lambda (exps builder)
89    (let cps-of-rest ((exps exps))
90      ;; cps-of-rest : Listof(InpExp) -> TfExp
91      (let ((pos (list-index
92                  (lambda (exp)
93                    (not (inp-exp-simple? exp)))
94                  exps)))
95        (if (not pos)
96            (builder (map cps-of-simple-exp exps))
97            (let ((var (fresh-identifier 'var)))
98              (cps-of-exp
99               (list-ref exps pos)
100               (cps-proc-exp (list var)
101                             (cps-of-rest
102                              (list-set exps pos (var-exp var)))))))))))
103
104;; inp-exp-simple? : InpExp -> Bool
105;; returns #t or #f, depending on whether exp would be a
106;; simple-exp if reparsed using the CPS-OUT language.
107(define inp-exp-simple?
108  (lambda (exp)
109    (cases expression exp
110      (const-exp (num) #t)
111      (var-exp (var) #t)
112      (diff-exp (exp1 exp2)
113                (and
114                 (inp-exp-simple? exp1)
115                 (inp-exp-simple? exp2)))
116      (zero?-exp (exp1)
117                 (inp-exp-simple? exp1))
118      (proc-exp (ids exp) #t)
119      (sum-exp (exps)
120               (all-simple? exps))
121      (else #f))))
122
123(define all-simple?
124  (lambda (exps)
125    (if (null? exps)
126        #t
127        (and (inp-exp-simple? (car exps))
128             (all-simple? (cdr exps))))))
129
130
131;; takes a list of expressions and finds the position of the first
132;; one that is not a simple-exp, else returns #f
133(define index-of-first-non-simple
134  (lambda (exps)
135    (cond
136      ((null? exps) #f)
137      ((inp-exp-simple? (car exps))
138       (let ((pos (index-of-first-non-simple (cdr exps))))
139         (if pos
140             (+ pos 1) #f)))
141      (else 0))))
142
143;; cps-of-simple-exp : InpExp -> SimpleExp
144;; Page: 220
145;; assumes (inp-exp-simple? exp).
146(define cps-of-simple-exp
147  (lambda (exp)
148    (cases expression exp
149      (const-exp (num) (cps-const-exp num))
150      (var-exp (var) (cps-var-exp var))
151      (diff-exp (exp1 exp2)
152                (cps-diff-exp
153                 (cps-of-simple-exp exp1)
154                 (cps-of-simple-exp exp2)))
155      (zero?-exp (exp1)
156                 (cps-zero?-exp
157                  (cps-of-simple-exp exp1)))
158      (proc-exp (ids exp)
159                (cps-proc-exp (append ids (list 'k%00))
160                              (cps-of-exp exp (cps-var-exp 'k%00))))
161      (sum-exp (exps)
162               (cps-sum-exp
163                (map cps-of-simple-exp exps)))
164      (else
165       (report-invalid-exp-to-cps-of-simple-exp exp)))))
166
167(define report-invalid-exp-to-cps-of-simple-exp
168  (lambda (exp)
169    (eopl:error 'cps-simple-of-exp
170                "non-simple expression to cps-of-simple-exp: ~s"
171                exp)))
172
173;; make-send-to-cont : SimpleExp * SimpleExp -> TfExp
174;; Page: 214
175(define make-send-to-cont
176  (lambda (cont bexp)
177    (cps-call-exp cont (list bexp))))
178
179
180;; cps-of-zero?-exp : InpExp * SimpleExp -> TfExp
181;; Page: 222
182(define cps-of-zero?-exp
183  (lambda (exp1 k-exp)
184    (cps-of-exps (list exp1)
185                 (lambda (new-rands)
186                   (make-send-to-cont
187                    k-exp
188                    (cps-zero?-exp
189                     (car new-rands)))))))
190
191;; cps-of-sum-exp : Listof (InpExp) * SimpleExp -> TfExp
192;; Page: 219
193(define cps-of-sum-exp
194  (lambda (exps k-exp)
195    (cps-of-exps exps
196                 (lambda (new-rands)
197                   (make-send-to-cont
198                    k-exp
199                    (cps-sum-exp new-rands))))))
200
201;; cps-of-diff-exp : InpExp * InpExp * SimpleExp -> TfExp
202;; Page: 223
203(define cps-of-diff-exp
204  (lambda (exp1 exp2 k-exp)
205    (cps-of-exps
206     (list exp1 exp2)
207     (lambda (new-rands)
208       (make-send-to-cont
209        k-exp
210        (cps-diff-exp
211         (car new-rands)
212         (cadr new-rands)))))))
213
214
215;; cps-of-if-exp : InpExp * InpExp * InpExp * SimpleExp -> TfExp
216;; Page: 223
217(define cps-of-if-exp
218  (lambda (exp1 exp2 exp3 k-exp)
219    (cps-of-exps (list exp1)
220                 (lambda (new-rands)
221                   (cps-if-exp (car new-rands)
222                               (cps-of-exp exp2 k-exp)
223                               (cps-of-exp exp3 k-exp))))))
224
225;; cps-of-let-exp : Var * InpExp * InpExp * SimpleExp -> TfExp
226;; Page: 222
227(define cps-of-let-exp
228  (lambda (id rhs body k-exp)
229    (cps-of-exps (list rhs)
230                 (lambda (new-rands)
231                   (cps-let-exp id
232                                (car new-rands)
233                                (cps-of-exp body k-exp))))))
234
235;; cps-of-letrec-exp :
236;; Listof(Listof(Var)) * Listof(InpExp) * InpExp * SimpleExp -> TfExp
237;; Page: 223
238(define cps-of-letrec-exp
239  (lambda (proc-names idss proc-bodies body k-exp)
240    (cps-letrec-exp
241     proc-names
242     (map
243      (lambda (ids) (append ids (list 'k%00)))
244      idss)
245     (map
246      (lambda (exp) (cps-of-exp exp (cps-var-exp 'k%00)))
247      proc-bodies)
248     (cps-of-exp body k-exp))))
249
250;; cps-of-call-exp : InpExp * Listof(InpExp) * SimpleExp -> TfExp
251;; Page: 220
252(define cps-of-call-exp
253  (lambda (rator rands k-exp)
254    (cps-of-exps (cons rator rands)
255                 (lambda (new-rands)
256                   (cps-call-exp
257                    (car new-rands)
258                    (append (cdr new-rands) (list k-exp)))))))
259
260;;;;;;;;;;;;;;;; utilities ;;;;;;;;;;;;;;;;
261
262(define fresh-identifier
263  (let ((sn 0))
264    (lambda (identifier)
265      (set! sn (+ sn 1))
266      (string->symbol
267       (string-append
268        (symbol->string identifier)
269        "%"             ; this can't appear in an input identifier
270        (number->string sn))))))
271
272;; list-set : SchemeList * Int * SchemeVal -> SchemeList
273;; returns a list lst1 that is just like lst, except that
274;; (listref lst1 n) = val.
275(define list-set
276  (lambda (lst n val)
277    (cond
278      ((null? lst) (eopl:error 'list-set "ran off end"))
279      ((zero? n) (cons val (cdr lst)))
280      (else (cons (car lst) (list-set (cdr lst) (- n 1) val))))))
281
282;; list-index : (SchemeVal -> Bool) * SchemeList -> Maybe(Int)
283;; returns the smallest number n such that (pred (listref lst n))
284;; is true.  If pred is false on every element of lst, then returns
285;; #f.
286(define list-index
287  (lambda (pred lst)
288    (cond
289      ((null? lst) #f)
290      ((pred (car lst)) 0)
291      ((list-index pred (cdr lst)) => (lambda (n) (+ n 1)))
292      (else #f))))
293
294