Merge commit 'f6ddf827f8f192af7a8cd255bd8374a0d38bbb74'
[bpt/guile.git] / module / language / tree-il.scm
CommitLineData
19113f1c 1;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
d26a26f6 2;;;;
811d10f5
AW
3;;;; This library is free software; you can redistribute it and/or
4;;;; modify it under the terms of the GNU Lesser General Public
5;;;; License as published by the Free Software Foundation; either
53befeb7 6;;;; version 3 of the License, or (at your option) any later version.
d26a26f6 7;;;;
811d10f5
AW
8;;;; This library is distributed in the hope that it will be useful,
9;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11;;;; Lesser General Public License for more details.
d26a26f6 12;;;;
811d10f5
AW
13;;;; You should have received a copy of the GNU Lesser General Public
14;;;; License along with this library; if not, write to the Free Software
15;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
d26a26f6 16;;;;
811d10f5
AW
17\f
18
19(define-module (language tree-il)
f4aa0f10 20 #:use-module (srfi srfi-1)
4dcd8499 21 #:use-module (srfi srfi-11)
99b4da8f 22 #:use-module (ice-9 match)
811d10f5 23 #:use-module (system base syntax)
9efc833d 24 #:export (tree-il-src
811d10f5 25
cf10678f 26 <void> void? make-void void-src
81fd3152 27 <const> const? make-const const-src const-exp
cb28c085
AW
28 <primitive-ref> primitive-ref? make-primitive-ref primitive-ref-src primitive-ref-name
29 <lexical-ref> lexical-ref? make-lexical-ref lexical-ref-src lexical-ref-name lexical-ref-gensym
30 <lexical-set> lexical-set? make-lexical-set lexical-set-src lexical-set-name lexical-set-gensym lexical-set-exp
31 <module-ref> module-ref? make-module-ref module-ref-src module-ref-mod module-ref-name module-ref-public?
32 <module-set> module-set? make-module-set module-set-src module-set-mod module-set-name module-set-public? module-set-exp
33 <toplevel-ref> toplevel-ref? make-toplevel-ref toplevel-ref-src toplevel-ref-name
34 <toplevel-set> toplevel-set? make-toplevel-set toplevel-set-src toplevel-set-name toplevel-set-exp
35 <toplevel-define> toplevel-define? make-toplevel-define toplevel-define-src toplevel-define-name toplevel-define-exp
b6d93b11 36 <conditional> conditional? make-conditional conditional-src conditional-test conditional-consequent conditional-alternate
7081d4f9 37 <call> call? make-call call-src call-proc call-args
a881a4ae 38 <primcall> primcall? make-primcall primcall-src primcall-name primcall-args
d019ef92 39 <seq> seq? make-seq seq-src seq-head seq-tail
8a4ca0ea
AW
40 <lambda> lambda? make-lambda lambda-src lambda-meta lambda-body
41 <lambda-case> lambda-case? make-lambda-case lambda-case-src
178a4092 42 ;; idea: arity
b0c8c187 43 lambda-case-req lambda-case-opt lambda-case-rest lambda-case-kw
93f63467 44 lambda-case-inits lambda-case-gensyms
3a88cb3b 45 lambda-case-body lambda-case-alternate
93f63467 46 <let> let? make-let let-src let-names let-gensyms let-vals let-body
fb6e61ca 47 <letrec> letrec? make-letrec letrec-src letrec-in-order? letrec-names letrec-gensyms letrec-vals letrec-body
93f63467 48 <fix> fix? make-fix fix-src fix-names fix-gensyms fix-vals fix-body
8a4ca0ea 49 <let-values> let-values? make-let-values let-values-src let-values-exp let-values-body
178a4092 50 <prompt> prompt? make-prompt prompt-src prompt-escape-only? prompt-tag prompt-body prompt-handler
2d026f04 51 <abort> abort? make-abort abort-src abort-tag abort-args abort-tail
f4aa0f10 52
6fc3eae4
AW
53 list->seq
54
9efc833d
AW
55 parse-tree-il
56 unparse-tree-il
cb28c085
AW
57 tree-il->scheme
58
f4aa0f10 59 tree-il-fold
4dcd8499 60 make-tree-il-folder
403d78f9 61 post-order
25450a0d 62 pre-order
1fb39dc5
AW
63
64 tree-il=?
65 tree-il-hash))
811d10f5 66
4ffa8275 67(define (print-tree-il exp port)
7cd6d77c 68 (format port "#<tree-il ~S>" (unparse-tree-il exp)))
4ffa8275 69
f7b61b39
AW
70(define-syntax borrow-core-vtables
71 (lambda (x)
72 (syntax-case x ()
73 ((_)
74 (let lp ((n 0) (out '()))
75 (if (< n (vector-length %expanded-vtables))
76 (lp (1+ n)
77 (let* ((vtable (vector-ref %expanded-vtables n))
78 (stem (struct-ref vtable (+ vtable-offset-user 0)))
79 (fields (struct-ref vtable (+ vtable-offset-user 2)))
80 (sfields (map
81 (lambda (f) (datum->syntax x f))
82 fields))
83 (type (datum->syntax x (symbol-append '< stem '>)))
84 (ctor (datum->syntax x (symbol-append 'make- stem)))
85 (pred (datum->syntax x (symbol-append stem '?))))
86 (let lp ((n 0) (fields fields)
87 (out (cons*
88 #`(define (#,ctor #,@sfields)
89 (make-struct #,type 0 #,@sfields))
90 #`(define (#,pred x)
91 (and (struct? x)
92 (eq? (struct-vtable x) #,type)))
4ffa8275
AW
93 #`(struct-set! #,type vtable-index-printer
94 print-tree-il)
f7b61b39
AW
95 #`(define #,type
96 (vector-ref %expanded-vtables #,n))
97 out)))
98 (if (null? fields)
99 out
100 (lp (1+ n)
101 (cdr fields)
102 (let ((acc (datum->syntax
103 x (symbol-append stem '- (car fields)))))
104 (cons #`(define #,acc
105 (make-procedure-with-setter
106 (lambda (x) (struct-ref x #,n))
107 (lambda (x v) (struct-set! x #,n v))))
108 out)))))))
109 #`(begin #,@(reverse out))))))))
110
111(borrow-core-vtables)
112
113 ;; (<void>)
114 ;; (<const> exp)
115 ;; (<primitive-ref> name)
116 ;; (<lexical-ref> name gensym)
117 ;; (<lexical-set> name gensym exp)
118 ;; (<module-ref> mod name public?)
119 ;; (<module-set> mod name public? exp)
120 ;; (<toplevel-ref> name)
121 ;; (<toplevel-set> name exp)
122 ;; (<toplevel-define> name exp)
123 ;; (<conditional> test consequent alternate)
7081d4f9 124 ;; (<call> proc args)
a881a4ae 125 ;; (<primcall> name args)
6fc3eae4 126 ;; (<seq> head tail)
f7b61b39
AW
127 ;; (<lambda> meta body)
128 ;; (<lambda-case> req opt rest kw inits gensyms body alternate)
129 ;; (<let> names gensyms vals body)
fb6e61ca 130 ;; (<letrec> in-order? names gensyms vals body)
f7b61b39 131
4ffa8275 132(define-type (<tree-il> #:common-slots (src) #:printer print-tree-il)
93f63467 133 (<fix> names gensyms vals body)
1c297a38 134 (<let-values> exp body)
178a4092 135 (<prompt> escape-only? tag body handler)
2d026f04 136 (<abort> tag args tail))
d26a26f6 137
811d10f5
AW
138\f
139
6fc3eae4
AW
140;; A helper.
141(define (list->seq loc exps)
142 (if (null? (cdr exps))
143 (car exps)
144 (make-seq loc (car exps) (list->seq #f (cdr exps)))))
145
146\f
147
811d10f5
AW
148(define (location x)
149 (and (pair? x)
150 (let ((props (source-properties x)))
81fd3152 151 (and (pair? props) props))))
811d10f5 152
ce09ee19 153(define (parse-tree-il exp)
811d10f5 154 (let ((loc (location exp))
ce09ee19 155 (retrans (lambda (x) (parse-tree-il x))))
f852e05e
AW
156 (match exp
157 (('void)
cf10678f
AW
158 (make-void loc))
159
f852e05e 160 (('call proc . args)
7081d4f9 161 (make-call loc (retrans proc) (map retrans args)))
811d10f5 162
f852e05e 163 (('primcall name . args)
a881a4ae
AW
164 (make-primcall loc name (map retrans args)))
165
f852e05e 166 (('if test consequent alternate)
b6d93b11 167 (make-conditional loc (retrans test) (retrans consequent) (retrans alternate)))
811d10f5 168
f852e05e 169 (('primitive (and name (? symbol?)))
811d10f5
AW
170 (make-primitive-ref loc name))
171
f852e05e 172 (('lexical (and name (? symbol?)))
811d10f5
AW
173 (make-lexical-ref loc name name))
174
f852e05e 175 (('lexical (and name (? symbol?)) (and sym (? symbol?)))
811d10f5
AW
176 (make-lexical-ref loc name sym))
177
f852e05e 178 (('set! ('lexical (and name (? symbol?))) exp)
5c27902e
AW
179 (make-lexical-set loc name name (retrans exp)))
180
f852e05e 181 (('set! ('lexical (and name (? symbol?)) (and sym (? symbol?))) exp)
811d10f5
AW
182 (make-lexical-set loc name sym (retrans exp)))
183
f852e05e 184 (('@ ((and mod (? symbol?)) ...) (and name (? symbol?)))
811d10f5
AW
185 (make-module-ref loc mod name #t))
186
f852e05e 187 (('set! ('@ ((and mod (? symbol?)) ...) (and name (? symbol?))) exp)
811d10f5
AW
188 (make-module-set loc mod name #t (retrans exp)))
189
f852e05e 190 (('@@ ((and mod (? symbol?)) ...) (and name (? symbol?)))
811d10f5
AW
191 (make-module-ref loc mod name #f))
192
f852e05e 193 (('set! ('@@ ((and mod (? symbol?)) ...) (and name (? symbol?))) exp)
811d10f5
AW
194 (make-module-set loc mod name #f (retrans exp)))
195
f852e05e 196 (('toplevel (and name (? symbol?)))
811d10f5
AW
197 (make-toplevel-ref loc name))
198
f852e05e 199 (('set! ('toplevel (and name (? symbol?))) exp)
811d10f5
AW
200 (make-toplevel-set loc name (retrans exp)))
201
f852e05e 202 (('define (and name (? symbol?)) exp)
811d10f5
AW
203 (make-toplevel-define loc name (retrans exp)))
204
f852e05e 205 (('lambda meta body)
8a4ca0ea 206 (make-lambda loc meta (retrans body)))
811d10f5 207
f852e05e 208 (('lambda-case ((req opt rest kw inits gensyms) body) alternate)
d26a26f6 209 (make-lambda-case loc req opt rest kw
93f63467 210 (map retrans inits) gensyms
8a4ca0ea 211 (retrans body)
3a88cb3b 212 (and=> alternate retrans)))
811d10f5 213
f852e05e 214 (('lambda-case ((req opt rest kw inits gensyms) body))
b0c8c187 215 (make-lambda-case loc req opt rest kw
93f63467 216 (map retrans inits) gensyms
7e01997e
AW
217 (retrans body)
218 #f))
219
f852e05e 220 (('const exp)
811d10f5
AW
221 (make-const loc exp))
222
f852e05e 223 (('seq head tail)
6fc3eae4
AW
224 (make-seq loc (retrans head) (retrans tail)))
225
226 ;; Convenience.
f852e05e 227 (('begin . exps)
6fc3eae4 228 (list->seq loc (map retrans exps)))
811d10f5 229
f852e05e 230 (('let names gensyms vals body)
93f63467 231 (make-let loc names gensyms (map retrans vals) (retrans body)))
f4aa8d53 232
f852e05e 233 (('letrec names gensyms vals body)
fb6e61ca
AW
234 (make-letrec loc #f names gensyms (map retrans vals) (retrans body)))
235
f852e05e 236 (('letrec* names gensyms vals body)
fb6e61ca 237 (make-letrec loc #t names gensyms (map retrans vals) (retrans body)))
811d10f5 238
f852e05e 239 (('fix names gensyms vals body)
93f63467 240 (make-fix loc names gensyms (map retrans vals) (retrans body)))
c21c89b1 241
f852e05e 242 (('let-values exp body)
8a4ca0ea 243 (make-let-values loc (retrans exp) (retrans body)))
811d10f5 244
178a4092
AW
245 (('prompt escape-only? tag body handler)
246 (make-prompt loc escape-only?
247 (retrans tag) (retrans body) (retrans handler)))
f852e05e
AW
248
249 (('abort tag args tail)
2d026f04 250 (make-abort loc (retrans tag) (map retrans args) (retrans tail)))
1c297a38 251
811d10f5
AW
252 (else
253 (error "unrecognized tree-il" exp)))))
254
255(define (unparse-tree-il tree-il)
98f778ea
AW
256 (match tree-il
257 (($ <void> src)
cf10678f
AW
258 '(void))
259
98f778ea 260 (($ <call> src proc args)
7081d4f9 261 `(call ,(unparse-tree-il proc) ,@(map unparse-tree-il args)))
811d10f5 262
98f778ea 263 (($ <primcall> src name args)
a881a4ae
AW
264 `(primcall ,name ,@(map unparse-tree-il args)))
265
98f778ea
AW
266 (($ <conditional> src test consequent alternate)
267 `(if ,(unparse-tree-il test)
268 ,(unparse-tree-il consequent)
269 ,(unparse-tree-il alternate)))
811d10f5 270
98f778ea 271 (($ <primitive-ref> src name)
811d10f5
AW
272 `(primitive ,name))
273
98f778ea 274 (($ <lexical-ref> src name gensym)
811d10f5
AW
275 `(lexical ,name ,gensym))
276
98f778ea 277 (($ <lexical-set> src name gensym exp)
811d10f5
AW
278 `(set! (lexical ,name ,gensym) ,(unparse-tree-il exp)))
279
98f778ea 280 (($ <module-ref> src mod name public?)
811d10f5
AW
281 `(,(if public? '@ '@@) ,mod ,name))
282
98f778ea 283 (($ <module-set> src mod name public? exp)
811d10f5
AW
284 `(set! (,(if public? '@ '@@) ,mod ,name) ,(unparse-tree-il exp)))
285
98f778ea 286 (($ <toplevel-ref> src name)
811d10f5
AW
287 `(toplevel ,name))
288
98f778ea 289 (($ <toplevel-set> src name exp)
811d10f5
AW
290 `(set! (toplevel ,name) ,(unparse-tree-il exp)))
291
98f778ea 292 (($ <toplevel-define> src name exp)
811d10f5
AW
293 `(define ,name ,(unparse-tree-il exp)))
294
98f778ea 295 (($ <lambda> src meta body)
19113f1c
AW
296 (if body
297 `(lambda ,meta ,(unparse-tree-il body))
298 `(lambda ,meta (lambda-case))))
8a4ca0ea 299
98f778ea 300 (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
93f63467 301 `(lambda-case ((,req ,opt ,rest ,kw ,(map unparse-tree-il inits) ,gensyms)
8a4ca0ea 302 ,(unparse-tree-il body))
3a88cb3b 303 . ,(if alternate (list (unparse-tree-il alternate)) '())))
811d10f5 304
98f778ea 305 (($ <const> src exp)
811d10f5
AW
306 `(const ,exp))
307
98f778ea 308 (($ <seq> src head tail)
6fc3eae4
AW
309 `(seq ,(unparse-tree-il head) ,(unparse-tree-il tail)))
310
98f778ea 311 (($ <let> src names gensyms vals body)
93f63467 312 `(let ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
811d10f5 313
98f778ea 314 (($ <letrec> src in-order? names gensyms vals body)
fb6e61ca
AW
315 `(,(if in-order? 'letrec* 'letrec) ,names ,gensyms
316 ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
f4aa8d53 317
98f778ea 318 (($ <fix> src names gensyms vals body)
93f63467 319 `(fix ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
c21c89b1 320
98f778ea 321 (($ <let-values> src exp body)
1c297a38
AW
322 `(let-values ,(unparse-tree-il exp) ,(unparse-tree-il body)))
323
178a4092
AW
324 (($ <prompt> src escape-only? tag body handler)
325 `(prompt ,escape-only?
326 ,(unparse-tree-il tag)
98f778ea
AW
327 ,(unparse-tree-il body)
328 ,(unparse-tree-il handler)))
d26a26f6 329
98f778ea 330 (($ <abort> src tag args tail)
2d026f04
AW
331 `(abort ,(unparse-tree-il tag) ,(map unparse-tree-il args)
332 ,(unparse-tree-il tail)))))
811d10f5 333
72ee0ef7
MW
334(define* (tree-il->scheme e #:optional (env #f) (opts '()))
335 (values ((@ (language scheme decompile-tree-il)
336 decompile-tree-il)
337 e env opts)))
cb28c085 338
f4aa0f10 339\f
0c65f52c
AW
340(define-syntax-rule (make-tree-il-folder seed ...)
341 (lambda (tree down up seed ...)
342 (define (fold-values proc exps seed ...)
343 (if (null? exps)
344 (values seed ...)
345 (let-values (((seed ...) (proc (car exps) seed ...)))
346 (fold-values proc (cdr exps) seed ...))))
347 (let foldts ((tree tree) (seed seed) ...)
348 (let*-values
349 (((seed ...) (down tree seed ...))
350 ((seed ...)
b34b66b3
AW
351 (match tree
352 (($ <lexical-set> src name gensym exp)
0c65f52c 353 (foldts exp seed ...))
b34b66b3 354 (($ <module-set> src mod name public? exp)
0c65f52c 355 (foldts exp seed ...))
b34b66b3 356 (($ <toplevel-set> src name exp)
0c65f52c 357 (foldts exp seed ...))
b34b66b3 358 (($ <toplevel-define> src name exp)
0c65f52c 359 (foldts exp seed ...))
b34b66b3 360 (($ <conditional> src test consequent alternate)
0c65f52c
AW
361 (let*-values (((seed ...) (foldts test seed ...))
362 ((seed ...) (foldts consequent seed ...)))
363 (foldts alternate seed ...)))
b34b66b3 364 (($ <call> src proc args)
0c65f52c
AW
365 (let-values (((seed ...) (foldts proc seed ...)))
366 (fold-values foldts args seed ...)))
b34b66b3 367 (($ <primcall> src name args)
ca128245 368 (fold-values foldts args seed ...))
b34b66b3 369 (($ <seq> src head tail)
ca128245
AW
370 (let-values (((seed ...) (foldts head seed ...)))
371 (foldts tail seed ...)))
b34b66b3 372 (($ <lambda> src meta body)
19113f1c
AW
373 (if body
374 (foldts body seed ...)
375 (values seed ...)))
b34b66b3
AW
376 (($ <lambda-case> src req opt rest kw inits gensyms body
377 alternate)
0c65f52c
AW
378 (let-values (((seed ...) (fold-values foldts inits seed ...)))
379 (if alternate
380 (let-values (((seed ...) (foldts body seed ...)))
381 (foldts alternate seed ...))
382 (foldts body seed ...))))
b34b66b3 383 (($ <let> src names gensyms vals body)
0c65f52c
AW
384 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
385 (foldts body seed ...)))
b34b66b3 386 (($ <letrec> src in-order? names gensyms vals body)
0c65f52c
AW
387 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
388 (foldts body seed ...)))
b34b66b3 389 (($ <fix> src names gensyms vals body)
0c65f52c
AW
390 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
391 (foldts body seed ...)))
b34b66b3 392 (($ <let-values> src exp body)
0c65f52c
AW
393 (let*-values (((seed ...) (foldts exp seed ...)))
394 (foldts body seed ...)))
178a4092 395 (($ <prompt> src escape-only? tag body handler)
0c65f52c
AW
396 (let*-values (((seed ...) (foldts tag seed ...))
397 ((seed ...) (foldts body seed ...)))
398 (foldts handler seed ...)))
b34b66b3 399 (($ <abort> src tag args tail)
0c65f52c
AW
400 (let*-values (((seed ...) (foldts tag seed ...))
401 ((seed ...) (fold-values foldts args seed ...)))
402 (foldts tail seed ...)))
b34b66b3 403 (_
0c65f52c
AW
404 (values seed ...)))))
405 (up tree seed ...)))))
4dcd8499 406
007f671a
AW
407(define (tree-il-fold down up seed tree)
408 "Traverse TREE, calling DOWN before visiting a sub-tree, and UP when
409after visiting it. Each of these procedures is invoked as `(PROC TREE
410SEED)', where TREE is the sub-tree considered and SEED is the current
411result, intially seeded with SEED.
412
413This is an implementation of `foldts' as described by Andy Wingo in
414``Applications of fold to XML transformation''."
415 ;; Multi-valued fold naturally puts the seeds at the end, whereas
416 ;; normal fold puts the traversable at the end. Adapt to the expected
417 ;; argument order.
418 ((make-tree-il-folder tree) tree down up seed))
419
403d78f9 420(define (pre-post-order pre post x)
cb28c085 421 (let lp ((x x))
403d78f9 422 (post
99b4da8f
AW
423 (match (pre x)
424 (($ <void> src)
403d78f9 425 (make-void src))
cb28c085 426
99b4da8f 427 (($ <const> src exp)
403d78f9 428 (make-const src exp))
a881a4ae 429
99b4da8f 430 (($ <primitive-ref> src name)
403d78f9 431 (make-primitive-ref src name))
d26a26f6 432
99b4da8f 433 (($ <lexical-ref> src name gensym)
403d78f9 434 (make-lexical-ref src name gensym))
d26a26f6 435
99b4da8f 436 (($ <lexical-set> src name gensym exp)
403d78f9 437 (make-lexical-set src name gensym (lp exp)))
d26a26f6 438
99b4da8f 439 (($ <module-ref> src mod name public?)
403d78f9 440 (make-module-ref src mod name public?))
d26a26f6 441
99b4da8f 442 (($ <module-set> src mod name public? exp)
403d78f9 443 (make-module-set src mod name public? (lp exp)))
d26a26f6 444
99b4da8f 445 (($ <toplevel-ref> src name)
403d78f9 446 (make-toplevel-ref src name))
d26a26f6 447
99b4da8f 448 (($ <toplevel-set> src name exp)
403d78f9 449 (make-toplevel-set src name (lp exp)))
d26a26f6 450
99b4da8f 451 (($ <toplevel-define> src name exp)
403d78f9
AW
452 (make-toplevel-define src name (lp exp)))
453
99b4da8f 454 (($ <conditional> src test consequent alternate)
403d78f9
AW
455 (make-conditional src (lp test) (lp consequent) (lp alternate)))
456
99b4da8f 457 (($ <call> src proc args)
403d78f9
AW
458 (make-call src (lp proc) (map lp args)))
459
99b4da8f 460 (($ <primcall> src name args)
403d78f9
AW
461 (make-primcall src name (map lp args)))
462
99b4da8f 463 (($ <seq> src head tail)
403d78f9 464 (make-seq src (lp head) (lp tail)))
6fc3eae4 465
99b4da8f 466 (($ <lambda> src meta body)
403d78f9
AW
467 (make-lambda src meta (and body (lp body))))
468
99b4da8f 469 (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
403d78f9
AW
470 (make-lambda-case src req opt rest kw (map lp inits) gensyms (lp body)
471 (and alternate (lp alternate))))
472
99b4da8f 473 (($ <let> src names gensyms vals body)
403d78f9
AW
474 (make-let src names gensyms (map lp vals) (lp body)))
475
99b4da8f 476 (($ <letrec> src in-order? names gensyms vals body)
403d78f9
AW
477 (make-letrec src in-order? names gensyms (map lp vals) (lp body)))
478
99b4da8f 479 (($ <fix> src names gensyms vals body)
403d78f9
AW
480 (make-fix src names gensyms (map lp vals) (lp body)))
481
99b4da8f 482 (($ <let-values> src exp body)
403d78f9
AW
483 (make-let-values src (lp exp) (lp body)))
484
178a4092
AW
485 (($ <prompt> src escape-only? tag body handler)
486 (make-prompt src escape-only? (lp tag) (lp body) (lp handler)))
403d78f9 487
99b4da8f 488 (($ <abort> src tag args tail)
403d78f9
AW
489 (make-abort src (lp tag) (map lp args) (lp tail)))))))
490
491(define (post-order f x)
492 (pre-post-order (lambda (x) x) f x))
cb28c085 493
25450a0d
AW
494(define (pre-order f x)
495 (pre-post-order f (lambda (x) x) x))
1fb39dc5
AW
496
497;; FIXME: We should have a better primitive than this.
498(define (struct-nfields x)
499 (/ (string-length (symbol->string (struct-layout x))) 2))
500
501(define (tree-il=? a b)
502 (cond
503 ((struct? a)
504 (and (struct? b)
505 (eq? (struct-vtable a) (struct-vtable b))
506 ;; Assume that all structs are tree-il, so we skip over the
507 ;; src slot.
508 (let lp ((n (1- (struct-nfields a))))
509 (or (zero? n)
510 (and (tree-il=? (struct-ref a n) (struct-ref b n))
511 (lp (1- n)))))))
512 ((pair? a)
513 (and (pair? b)
514 (tree-il=? (car a) (car b))
515 (tree-il=? (cdr a) (cdr b))))
516 (else
517 (equal? a b))))
518
519(define-syntax hash-bits
520 (make-variable-transformer
521 (lambda (x)
522 (syntax-case x ()
523 (var
524 (identifier? #'var)
525 (logcount most-positive-fixnum))))))
526
527(define (tree-il-hash exp)
528 (let ((hash-depth 4)
529 (hash-width 3))
530 (define (hash-exp exp depth)
531 (define (rotate x bits)
532 (logior (ash x (- bits))
533 (ash (logand x (1- (ash 1 bits))) (- hash-bits bits))))
534 (define (mix h1 h2)
535 (logxor h1 (rotate h2 8)))
536 (define (hash-struct s)
537 (let ((len (struct-nfields s))
538 (h (hashq (struct-vtable s) most-positive-fixnum)))
539 (if (zero? depth)
540 h
541 (let lp ((i (max (- len hash-width) 1)) (h h))
542 (if (< i len)
543 (lp (1+ i) (mix (hash-exp (struct-ref s i) (1+ depth)) h))
544 h)))))
545 (define (hash-list l)
546 (let ((h (hashq 'list most-positive-fixnum)))
547 (if (zero? depth)
548 h
549 (let lp ((l l) (width 0) (h h))
550 (if (< width hash-width)
551 (lp (cdr l) (1+ width)
552 (mix (hash-exp (car l) (1+ depth)) h))
553 h)))))
554 (cond
555 ((struct? exp) (hash-struct exp))
556 ((list? exp) (hash-list exp))
557 (else (hash exp most-positive-fixnum))))
558
559 (hash-exp exp 0)))