-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcogen-residual.scm
285 lines (244 loc) · 7.55 KB
/
cogen-residual.scm
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
;;; cogen-residual.scm
;;; copyright © 1996, 1997, 1998, 1999 by Peter Thiemann
;;; non-commercial use is free as long as the original copright notice
;;; remains intact
;;; functions to construct residual code
(define (make-residual-apply fn fa)
(cond
((and (pair? fa) (eq? (car fa) 'QUOTE) (eq? (cadr fa) '()))
`(,fn))
((and (pair? fa) (eq? (car fa) 'LIST))
`(,fn ,@(cdr fa)))
(else
`(APPLY ,fn ,fa))))
(define (make-residual-let var exp body)
(cond
((null? (gensym-local-hold))
(let ((new-def
(if (and (pair? exp) (eq? (car exp) 'BEGIN))
`(DEFINE ,var ,@(cdr exp))
`(DEFINE ,var ,exp))))
(add-to-residual-program! new-def))
body)
((eq? var body)
exp)
((and (pair? exp) ; kludge
(eq? (car exp) 'SET!))
(if (and (pair? body) (eq? (car body) 'BEGIN))
`(BEGIN ,exp ,@(cdr body))
`(BEGIN ,exp ,body)))
((and (pair? body) (memq (car body) '(LET LET*)))
(let ((header (cadr body))
(bodies (cddr body)))
`(LET* ((,var ,exp) ,@header) ,@bodies)))
((and (pair? body) (eq? (car body) 'BEGIN))
`(LET ((,var ,exp)) ,@(cdr body)))
((and (pair? body) (eq? (car body) 'OR) (eqv? var (cadr body)))
`(OR ,exp ,@(cddr body))) ;unsafe: no guarantee that var does not occur in body
(else
`(LET ((,var ,exp)) ,body))))
(define (make-residual-let-serious var proc args body)
(make-residual-let var (apply make-residual-call proc args)
body))
(define (make-residual-let-serious-apply var proc arg body)
(make-residual-let var (make-residual-apply proc arg)
body))
(define make-residual-let-trivial make-residual-let)
(define (make-residual-begin exp1 exp2)
(if (and (pair? exp1) (not (eq? (car exp1) 'QUOTE)))
(let ((exp2-begin (and (pair? exp2) (eq? (car exp2) 'BEGIN))))
(cond
((eq? (car exp1) 'BEGIN)
(if exp2-begin
`(BEGIN ,@(cdr exp1) ,@(cdr exp2))
`(BEGIN ,@(cdr exp1) ,exp2)))
(else
(if exp2-begin
`(BEGIN ,exp1 ,@(cdr exp2))
`(BEGIN ,exp1 ,exp2)))))
exp2))
(define (make-residual-cons exp1 exp2)
(if (pair? exp2)
(let ((tag (car exp2)))
(cond
((and (eq? tag 'QUOTE) (eq? (cadr exp2) '()))
`(LIST ,exp1))
((eq? tag 'LIST)
`(LIST ,exp1 ,@(cdr exp2)))
(else
`(CONS ,exp1 ,exp2))))
`(CONS ,exp1 ,exp2)))
(define (make-residual-generator-ve* name lv . args)
`(,name ,lv ,@args))
(define (make-residual-generator-vve* name lv x1 . args)
`(,name ,lv ,x1 ,@args))
(define (make-residual-generator-vve name v1 v2 e1)
`(,name ,v1 ,v2 ,e1))
(define (make-residual-generator-vvve* name lv v1 v2 v3 . e1*)
`(,name ,lv ,v1 ,v2 ,v3 ,@e1*))
(define (make-residual-generator-veve* name lv v1 e1 v2 . e2*)
`(,name ,lv ,v1 ,e1 ,v2 ,@e2*))
(define (make-residual-generator-vvvve name lv v1 v2 v3 v4 e1)
`(,name ,lv ,v1 ,v2 ,v3 ,v4 ,e1))
(define (make-residual-generator-vvee name lv v1 v2 e1 e2)
`(,name ,lv ,v1 ,v2 ,e1 ,e2))
(define (make-residual-generator-vveqe name lv v1 v2 e1 q1 e2)
`(,name ,lv ,v1 ,v2 ,e1 ',q1 ,e2))
(define (make-residual-generator-vqqeqe name v1 q1 q2 e1 q3 e2)
`(,name ,v1 ',q1 ',q2 ,e1 ',q3 ,e2))
(define (make-residual-generator-vqqqeqe name lv q1 q2 q3 x4 q5 x6)
`(,name ,lv ',q1 ',q2 ',q3 ,x4 ',q5 ,x6))
(define (make-residual-define-data lv arg)
(add-to-support-code! `(define-data ,@arg))
(if (zero? lv)
'pooof ;ignored
`(_OP ,(- lv 1) _DEFINE_DATA `,arg)))
(define (make-residual-define-mutable lv var arg)
(add-to-support-code! `(define ,var ,arg))
(if (zero? lv)
'pooof ;ignored
`(_OP ,(- lv 1) _DEFINE ,var ,arg)))
(define (make-branch branch)
(let ((code (cadr branch)))
(if (and (pair? code)
(eq? 'BEGIN (car code)))
(cons (car branch)
(cdr code))
branch)))
(define (constant-expression? exp)
(cond
((boolean? exp) #t)
((number? exp) #t)
((char? exp) #t)
((string? exp) #t)
((and (pair? exp)
(eq? 'QUOTE (car exp)))
#t)
(else #f)))
(define (constant-expression-constant exp)
(if (pair? exp)
(cadr exp)
exp))
(define (detect-constant-test test)
(and
(pair? test)
(case (car test)
((EQV?)
(cond
((constant-expression? (cadr test))
(cons
(caddr test)
(list (constant-expression-constant (cadr test)))))
((constant-expression? (caddr test))
(cons
(cadr test)
(list (constant-expression-constant (caddr test)))))
(else #f)))
((MEMV)
(cond
((constant-expression? (caddr test))
(cons
(cadr test)
(constant-expression-constant (caddr test))))
(else
#f)))
(else
#f))))
(define (make-residual-if c t e)
(cond
((eq? c #t)
t)
((eq? c #f)
e)
((eq? e #f)
(if (and (pair? t) (eq? 'AND (car t)))
`(AND ,c ,@(cdr t))
`(AND ,c ,t)))
((detect-constant-test c)
=> (lambda (stuff)
(let ((exp (car stuff))
(constants (cdr stuff)))
(if (and (pair? e) (eq? 'CASE (car e))
(equal? (cadr e) exp))
(make-residual-case
exp
(cons (make-branch `(,constants ,t))
(cddr e)))
(make-residual-case
exp
(cons (make-branch `(,constants ,t))
`((else ,e))))))))
((eqv? c t)
(if (and (pair? e) (eq? 'OR (car e)))
`(OR ,c ,@(cdr e))
`(OR ,c ,e)))
((and (pair? e) (eq? 'IF (car e)))
`(COND
,(make-branch `(,c ,t))
(,(cadr e) ,(caddr e))
(else ,(cadddr e))))
((and (pair? e) (eq? 'COND (car e)))
`(COND
,(make-branch `(,c ,t))
,@(cdr e)))
(else
`(IF ,c ,t ,e))))
;; assumption: (not (null? branches))
(define (make-residual-case exp branches)
(let ((collapsed-branches
(let loop ((current-branch (car branches))
(branches (cdr branches))
(new-branches '()))
(if (not (null? branches))
(let ((new-branch (car branches)))
(if (and (not (eq? 'else (car new-branch)))
(equal? (cdr new-branch) (cdr current-branch)))
(loop (cons (append (car new-branch) (car current-branch))
(cdr current-branch))
(cdr branches)
new-branches)
(loop new-branch
(cdr branches)
(cons current-branch new-branches))))
(reverse (cons current-branch new-branches))))))
`(CASE ,exp ,@collapsed-branches)))
(define (make-residual-call f . args)
(cons f args))
(define (make-residual-primop op . args)
(cons op args))
(define (make-lambda-body-list body)
(if (and (pair? body) (eq? (car body) 'BEGIN))
(cdr body)
(list body)))
(define (make-residual-closed-lambda formals free body)
`(LAMBDA ,formals ,@(make-lambda-body-list body)))
(define (make-residual-lambda formals fvs body)
`(LAMBDA ,formals ,@(make-lambda-body-list body)))
(define (make-residual-literal val)
(if (or (number? val) (string? val) (boolean? val))
val
`(QUOTE ,val)))
;; we need this abstraction because we need to actually *do* something
;; when directly generating object code
(define (make-residual-variable name)
name)
(define (make-residual-definition! name formals body)
(let ((new-def
(if (and (pair? body) (eq? (car body) 'BEGIN))
`(DEFINE (,name ,@formals) ,@(cdr body))
`(DEFINE (,name ,@formals) ,body))))
(add-to-residual-program! new-def)))
;; kludge alert
(define (residual-definition-replace-name defn new-name)
(let* ((old-defn-template (take 2 defn))
(new-defn-template
(list (car old-defn-template)
(cons new-name (cdadr old-defn-template))))
(defn-body (list-tail defn 2)))
(append new-defn-template defn-body)))
(define (residual-wrap-internal-definitions def internal-defs)
(let* ((defn-template (take 2 def))
(defn-body (list-tail def 2)))
(append defn-template
internal-defs
defn-body)))