-
Notifications
You must be signed in to change notification settings - Fork 0
/
closure-convert.rkt
327 lines (241 loc) · 11.4 KB
/
closure-convert.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#lang racket
(require "cps-convert.rkt" "anf-convert.rkt" "desugar.rkt" "prims.rkt")
(provide closure-convert)
(define (λ-or-lambda? str)
(match str
[(or (== 'lambda) (== 'λ)) #t]
[else #f]))
; so that every λ becomes variadic
(define (simplify-λ exp)
; (displayln (~a "exp: " exp))
(match exp
[`(let ([,lhs ',datum]) ,elet)
`(let ([,lhs ',datum]) ,(simplify-λ elet))]
[`(let ([,lhs (prim ,op ,es ...)]) ,elet)
`(let ([,lhs (prim ,op ,@es)]) ,(simplify-λ elet))]
[`(let ([,lhs (apply-prim ,op ,e)]) ,elet)
`(let ([,lhs (apply-prim ,op ,e)]) ,(simplify-λ elet))]
[`(let ([,lhs (,(? λ-or-lambda?) (,args ...) ,elam)]) ,elet)
; (displayln (~a "lamargs: " (list 'lhs: lhs 'args: args 'elam: elam 'elet: elet)))
(define arglst (gensym 'arglst))
`(let ([,lhs (λ ,arglst
,(let loop ([args args]
[arglst arglst])
; (displayln (~a "listf: " (list 'args: args 'arglst: arglst)))
(cond
[(null? args) (simplify-λ elam)]
[else
(define newarg (gensym 'arg_lst))
`(let ([,(car args) (prim car ,arglst)])
(let ([,newarg (prim cdr ,arglst)])
,(loop (cdr args) newarg)))])))])
,(simplify-λ elet))]
[`(let ([,lhs (,(? λ-or-lambda?) ,arg ,elam)]) ,elet)
`(let ([,lhs (λ ,arg ,(simplify-λ elam))]) ,(simplify-λ elet))]
[`(let ([,lhs ,val]) ,elet)
`(let ([,lhs ,val]) ,(simplify-λ elet))]
[`(apply ,f ,args)
`(apply ,f ,args)]
[`(if ,grd ,texp ,fexp)
`(if ,grd ,(simplify-λ texp) ,(simplify-λ fexp))]
[`(,f ,es ...)
; (displayln (~a "app: " (cons f es)))
(define arg (gensym 'oldarg))
`(let ([,arg '()])
,(let loop ([es (reverse es)]
[oldarg arg])
;(displayln (~a "lst: " (list 'proc: f 'es: es 'arg: oldarg)))
(cond
[(null? es) `(apply ,f ,oldarg)]
[(pair? es)
(define newarg (gensym 'newarg))
`(let ([,newarg (prim cons ,(car es) ,oldarg)])
,(loop (cdr es) newarg))])))
]))
(define (let-bound-program exp)
(define (normalize-ae proc exp)
(let loop ([ae_lst exp]
[acc '()])
; (displayln (~a "ae_list: " ae_lst " acc: " acc "\n"))
(cond
[(null? ae_lst) (proc acc)]
[(pair? ae_lst)
(cond
[(symbol? (car ae_lst))
(loop (cdr ae_lst) (append acc `(,(car ae_lst))))]
[else
(define newarg (gensym 'id))
(let-bound-program
`(let ([,newarg ,(car ae_lst)])
,(loop (cdr ae_lst) (append acc `(,newarg)))))
])])))
(match exp
[`(let ([,lhs ',datum]) ,elet)
`(let ([,lhs ',datum]) ,(let-bound-program elet))]
[`(let ([,lhs (prim ,op ,es ...)]) ,elet)
(normalize-ae (λ (args)
`(let ([,lhs (prim ,op ,@args)])
,(let-bound-program elet))) es)]
[`(let ([,lhs (apply-prim ,op ,es ...)]) ,elet)
(normalize-ae (λ (args)
`(let ([,lhs (apply-prim ,op ,@args)])
,(let-bound-program elet)))
es)]
[`(let ([,lhs (,(? λ-or-lambda?) ,args ,elam)]) ,elet)
`(let ([,lhs (λ ,args ,(let-bound-program elam))])
,(let-bound-program elet))]
[`(let ([,lhs ,val]) ,elet)
`(let ([,lhs ,val]) ,(let-bound-program elet))]
[`(apply ,params ...) ; (params ...) => (,f ,args)
(normalize-ae (λ (args) `(apply ,@args)) params)]
[`(if ,grd ... ,texp ,fexp) ; converting grd to a list => (grd ...) ;)
(normalize-ae (λ (args)
`(if ,@args
,(let-bound-program texp)
,(let-bound-program fexp)))
grd)]
[(? symbol? x) (normalize-ae (λ (args) args) (list x))]
[`(,aes ...)
(normalize-ae (λ (args) args) aes)]))
(define (closure-convert exp)
; returns -> an updated expression, free variable set, procedure list
(define (bottomup-convert ex [procs '()])
(define (get-new-proc-body vars body env_name)
(let loop ([count 1]
[vars vars]
[acc_body body])
(match vars
[(? null? vars) acc_body]
[_
(loop
(+ 1 count)
(cdr vars)
`(let ([,(car vars) (env-lookup ,env_name ,count)]) ,acc_body)
)])))
(match ex
[`(let ([,lhs ',val]) ,body)
(match-define (list temp_body free_vars temp_procs) (bottomup-convert body procs))
(define final_vars_set (set-remove free_vars lhs))
(list `(let ([,lhs ',val]) ,temp_body) final_vars_set temp_procs)]
[`(let ([,lhs (prim ,op ,args ...)]) ,body)
(match-define (list temp_body free_vars temp_procs) (bottomup-convert body procs))
(define rmv_duplicates (list->set args))
(define combined_args (set-union free_vars rmv_duplicates))
(define final_vars_set (set-remove combined_args lhs))
(list `(let ([,lhs (prim ,op ,@args)]) ,temp_body) final_vars_set temp_procs)]
[`(let ([,lhs (apply-prim ,op ,args)]) ,body)
(match-define (list temp_body free_vars temp_procs) (bottomup-convert body procs))
(define final_vars_set (set-remove (set-add free_vars args) lhs))
(list `(let ([,lhs (apply-prim ,op ,args)]) ,temp_body)
final_vars_set
temp_procs)]
[`(let ([,lhs (λ ,(? symbol? args) ,lam-body)]) ,let-body)
(define code_ptr (gensym 'ptr))
(define env_name (gensym 'env))
(match-define (list temp_body1 free_let_vars temp_procs1) (bottomup-convert let-body procs))
(match-define (list temp_body2 free_lam_vars temp_procs2) (bottomup-convert lam-body temp_procs1))
;AE ::= ... | (λ env_x args_x E) | (λ env_x (x ...) E)
;Proc ::= ... | (proc name env_x args_x E) | (proc name env_x (x ...) E)
(define final_env_vars (set-subtract free_lam_vars (set args)))
(define sorted_env_vars (set->list final_env_vars))
(define new-body (get-new-proc-body sorted_env_vars temp_body2 env_name))
(define combined_args (set-union free_let_vars final_env_vars))
(define final_vars_set (set-remove combined_args lhs))
(list `(let ([,lhs (new-closure ,code_ptr ,@sorted_env_vars)]) ,temp_body1)
final_vars_set
(cons `(proc ,code_ptr ,env_name ,args ,new-body) temp_procs2))]
#;[`(let ([,lhs (λ (,args ...) ,lam-body)]) ,let-body)
(define code_ptr (gensym 'ptr))
(define env_name (gensym 'env))
(match-define (list temp_body1 free_let_vars temp_procs1) (bottomup-convert let-body procs))
(match-define (list temp_body2 free_lam_vars temp_procs2) (bottomup-convert lam-body temp_procs1))
(define final_env_vars (set-subtract free_lam_vars (list->set args)))
(define sorted_env_vars (set->list final_env_vars))
(define new-body (get-new-proc-body sorted_env_vars temp_body2 env_name))
(define combined_args (set-union free_let_vars final_env_vars))
(define final_vars_set (set-remove combined_args lhs))
; (displayln (~a "letvars: " free_let_vars))
; (displayln (~a "free_lam_vars " free_lam_vars))
; (displayln (~a "final_vars_set: " final_vars_set))
; (displayln (~a "sorted_env_vars " sorted_env_vars))
; (displayln (~a "args " (list->set args)))
; (list `(let ([,lhs (new-closure ,code_ptr ,@(set->list final_vars_set))]) ,temp_body1)
(list `(let ([,lhs (new-closure ,code_ptr ,@sorted_env_vars)]) ,temp_body1)
final_vars_set
(cons `(proc ,code_ptr ,env_name (,@args) ,new-body) temp_procs2))]
[`(let ([,lhs ,val]) ,body)
(match-define (list temp_body free_vars temp_procs) (bottomup-convert body procs))
(define final_vars_set (set-remove free_vars lhs))
(list `(let ([,lhs ,val]) ,temp_body) final_vars_set temp_procs)]
[`(if ,grd ,texp ,fexp)
(match-define (list texp-body texp-free texp-procs) (bottomup-convert texp procs))
(match-define (list fexp-body fexp-free fexp-procs) (bottomup-convert fexp texp-procs))
(define final_vars_set (set-union fexp-free texp-free (set grd)))
(list `(if ,grd ,texp-body ,fexp-body)
final_vars_set
fexp-procs)]
[`(apply ,f ,args)
(define final_vars_set (list->set (cons f (cons args '()))))
(list `(app-clo ,f ,args) final_vars_set procs)]
#;[`(,f ,es ...)
(define final_vars_set (list->set (cons f es)))
(list `(app-clo ,f ,@es) final_vars_set procs)]
[_ (error (format "unknown expression '~a" ex))]
))
(define let_bounded_prog (let-bound-program exp))
(define lam_simplified_prog (simplify-λ let_bounded_prog))
; (pretty-print let_bounded_prog)
; (pretty-print lam_simplified_prog)
(match-define (list root_body free_vars procs) (bottomup-convert lam_simplified_prog))
; (define let_bounded_prog (let-bound-program (cps-convert (anf-convert (desugar (add-prims-to-prog exp))))))
; (pretty-print let_bounded_prog)
; (match-define (list root_body free_vars procs) (bottomup-convert (simplify-λ let_bounded_prog)))
; (pretty-print (let-bound-program exp))
; (pretty-print (simplify-λ (let-bound-program exp)))
; (when (not (set-empty? free_vars)) (displayln `(root_fv: ,free_vars)))
(cons `(proc root ,(gensym 'rootenv) ,(gensym 'rootarg) ,root_body) procs)
)
;;; tests
(define example
'(let ([d 2])
(let ([c (λ (x) (x))])
(let ([f (λ (b d) (+ d e b))])
(f k)))))
; (pretty-print (closure-convert example))
(define example1
'(let ([a 6])
(let ([d '2])
(let ([e '3])
(let ([c (λ (x) (+ x a d))])
(let ([f (λ (a b) (c (+ e d a b)))])
(f 4 5)))))))
; (pretty-print (closure-convert example1))
(define example2
'(let ([a '6])
(let ([d '2])
(let ([e '3])
(let ([c (λ (x) (+ x a d))])
(let ([f (λ (a b) (+ e d a b))])
(f 4 5)))))))
; (pretty-print (closure-convert example2))
; (pretty-print (closure-convert '(+ 1 2)))
; (pretty-print (closure-convert (cps-convert (anf-convert (desugar (add-prims-to-prog '(+ 1 2)))))))
; (pretty-print (closure-convert (cps-convert (anf-convert (desugar (add-prims-to-prog example2))))))
(define example3
'(let ((* (λ args
(let ((kkont3042 (prim car args)))
(let ((args (prim cdr args)))
(let ((prm3043 (apply-prim * args)))
(kkont3042 prm3043 prm3043)))))))
(* 2 5)))
; (pretty-print (closure-convert example3))
(define example4 '(if '1 '2 #f))
; (pretty-print (closure-convert example4))
; (pretty-print (closure-convert (cps-convert (anf-convert (desugar (add-prims-to-prog '(+ 2 3)))))))
; (pretty-print (add-prims-to-prog example))
; (pretty-print (desugar (add-prims-to-prog example)))
; (pretty-print (anf-convert (desugar (add-prims-to-prog example))))
; (pretty-print (cps-convert (anf-convert (desugar (add-prims-to-prog example)))))
; (pretty-print (closure-convert (cps-convert (anf-convert (desugar (add-prims-to-prog example))))))
; (pretty-print (closure-convert (cps-convert (anf-convert (desugar (add-prims-to-prog example4))))))
; (pretty-print (cps-convert (anf-convert (desugar (add-prims-to-prog '(+ 2 3))))))