Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / module / language / tree-il.scm
1 ;;;; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
2 ;;;;
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
6 ;;;; version 3 of the License, or (at your option) any later version.
7 ;;;;
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.
12 ;;;;
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
16 ;;;;
17 \f
18
19 (define-module (language tree-il)
20 #:use-module (srfi srfi-1)
21 #:use-module (srfi srfi-11)
22 #:use-module (system base pmatch)
23 #:use-module (system base syntax)
24 #:export (tree-il-src
25
26 <void> void? make-void void-src
27 <const> const? make-const const-src const-exp
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
36 <conditional> conditional? make-conditional conditional-src conditional-test conditional-consequent conditional-alternate
37 <call> call? make-call call-src call-proc call-args
38 <primcall> primcall? make-primcall primcall-src primcall-name primcall-args
39 <seq> seq? make-seq seq-src seq-head seq-tail
40 <lambda> lambda? make-lambda lambda-src lambda-meta lambda-body
41 <lambda-case> lambda-case? make-lambda-case lambda-case-src
42 lambda-case-req lambda-case-opt lambda-case-rest lambda-case-kw
43 lambda-case-inits lambda-case-gensyms
44 lambda-case-body lambda-case-alternate
45 <let> let? make-let let-src let-names let-gensyms let-vals let-body
46 <letrec> letrec? make-letrec letrec-src letrec-in-order? letrec-names letrec-gensyms letrec-vals letrec-body
47 <fix> fix? make-fix fix-src fix-names fix-gensyms fix-vals fix-body
48 <let-values> let-values? make-let-values let-values-src let-values-exp let-values-body
49 <dynwind> dynwind? make-dynwind dynwind-src dynwind-winder dynwind-pre dynwind-body dynwind-post dynwind-unwinder
50 <dynlet> dynlet? make-dynlet dynlet-src dynlet-fluids dynlet-vals dynlet-body
51 <dynref> dynref? make-dynref dynref-src dynref-fluid
52 <dynset> dynset? make-dynset dynset-src dynset-fluid dynset-exp
53 <prompt> prompt? make-prompt prompt-src prompt-tag prompt-body prompt-handler
54 <abort> abort? make-abort abort-src abort-tag abort-args abort-tail
55
56 list->seq
57
58 parse-tree-il
59 unparse-tree-il
60 tree-il->scheme
61
62 tree-il-fold
63 make-tree-il-folder
64 post-order!
65 pre-order!
66
67 tree-il=?
68 tree-il-hash))
69
70 (define (print-tree-il exp port)
71 (format port "#<tree-il ~S>" (unparse-tree-il exp)))
72
73 (define-syntax borrow-core-vtables
74 (lambda (x)
75 (syntax-case x ()
76 ((_)
77 (let lp ((n 0) (out '()))
78 (if (< n (vector-length %expanded-vtables))
79 (lp (1+ n)
80 (let* ((vtable (vector-ref %expanded-vtables n))
81 (stem (struct-ref vtable (+ vtable-offset-user 0)))
82 (fields (struct-ref vtable (+ vtable-offset-user 2)))
83 (sfields (map
84 (lambda (f) (datum->syntax x f))
85 fields))
86 (type (datum->syntax x (symbol-append '< stem '>)))
87 (ctor (datum->syntax x (symbol-append 'make- stem)))
88 (pred (datum->syntax x (symbol-append stem '?))))
89 (let lp ((n 0) (fields fields)
90 (out (cons*
91 #`(define (#,ctor #,@sfields)
92 (make-struct #,type 0 #,@sfields))
93 #`(define (#,pred x)
94 (and (struct? x)
95 (eq? (struct-vtable x) #,type)))
96 #`(struct-set! #,type vtable-index-printer
97 print-tree-il)
98 #`(define #,type
99 (vector-ref %expanded-vtables #,n))
100 out)))
101 (if (null? fields)
102 out
103 (lp (1+ n)
104 (cdr fields)
105 (let ((acc (datum->syntax
106 x (symbol-append stem '- (car fields)))))
107 (cons #`(define #,acc
108 (make-procedure-with-setter
109 (lambda (x) (struct-ref x #,n))
110 (lambda (x v) (struct-set! x #,n v))))
111 out)))))))
112 #`(begin #,@(reverse out))))))))
113
114 (borrow-core-vtables)
115
116 ;; (<void>)
117 ;; (<const> exp)
118 ;; (<primitive-ref> name)
119 ;; (<lexical-ref> name gensym)
120 ;; (<lexical-set> name gensym exp)
121 ;; (<module-ref> mod name public?)
122 ;; (<module-set> mod name public? exp)
123 ;; (<toplevel-ref> name)
124 ;; (<toplevel-set> name exp)
125 ;; (<toplevel-define> name exp)
126 ;; (<conditional> test consequent alternate)
127 ;; (<call> proc args)
128 ;; (<primcall> name args)
129 ;; (<seq> head tail)
130 ;; (<lambda> meta body)
131 ;; (<lambda-case> req opt rest kw inits gensyms body alternate)
132 ;; (<let> names gensyms vals body)
133 ;; (<letrec> in-order? names gensyms vals body)
134 ;; (<dynlet> fluids vals body)
135
136 (define-type (<tree-il> #:common-slots (src) #:printer print-tree-il)
137 (<fix> names gensyms vals body)
138 (<let-values> exp body)
139 (<dynwind> winder pre body post unwinder)
140 (<dynref> fluid)
141 (<dynset> fluid exp)
142 (<prompt> tag body handler)
143 (<abort> tag args tail))
144
145 \f
146
147 ;; A helper.
148 (define (list->seq loc exps)
149 (if (null? (cdr exps))
150 (car exps)
151 (make-seq loc (car exps) (list->seq #f (cdr exps)))))
152
153 \f
154
155 (define (location x)
156 (and (pair? x)
157 (let ((props (source-properties x)))
158 (and (pair? props) props))))
159
160 (define (parse-tree-il exp)
161 (let ((loc (location exp))
162 (retrans (lambda (x) (parse-tree-il x))))
163 (pmatch exp
164 ((void)
165 (make-void loc))
166
167 ((call ,proc . ,args)
168 (make-call loc (retrans proc) (map retrans args)))
169
170 ((primcall ,name . ,args)
171 (make-primcall loc name (map retrans args)))
172
173 ((if ,test ,consequent ,alternate)
174 (make-conditional loc (retrans test) (retrans consequent) (retrans alternate)))
175
176 ((primitive ,name) (guard (symbol? name))
177 (make-primitive-ref loc name))
178
179 ((lexical ,name) (guard (symbol? name))
180 (make-lexical-ref loc name name))
181
182 ((lexical ,name ,sym) (guard (symbol? name) (symbol? sym))
183 (make-lexical-ref loc name sym))
184
185 ((set! (lexical ,name) ,exp) (guard (symbol? name))
186 (make-lexical-set loc name name (retrans exp)))
187
188 ((set! (lexical ,name ,sym) ,exp) (guard (symbol? name) (symbol? sym))
189 (make-lexical-set loc name sym (retrans exp)))
190
191 ((@ ,mod ,name) (guard (and-map symbol? mod) (symbol? name))
192 (make-module-ref loc mod name #t))
193
194 ((set! (@ ,mod ,name) ,exp) (guard (and-map symbol? mod) (symbol? name))
195 (make-module-set loc mod name #t (retrans exp)))
196
197 ((@@ ,mod ,name) (guard (and-map symbol? mod) (symbol? name))
198 (make-module-ref loc mod name #f))
199
200 ((set! (@@ ,mod ,name) ,exp) (guard (and-map symbol? mod) (symbol? name))
201 (make-module-set loc mod name #f (retrans exp)))
202
203 ((toplevel ,name) (guard (symbol? name))
204 (make-toplevel-ref loc name))
205
206 ((set! (toplevel ,name) ,exp) (guard (symbol? name))
207 (make-toplevel-set loc name (retrans exp)))
208
209 ((define ,name ,exp) (guard (symbol? name))
210 (make-toplevel-define loc name (retrans exp)))
211
212 ((lambda ,meta ,body)
213 (make-lambda loc meta (retrans body)))
214
215 ((lambda-case ((,req ,opt ,rest ,kw ,inits ,gensyms) ,body) ,alternate)
216 (make-lambda-case loc req opt rest kw
217 (map retrans inits) gensyms
218 (retrans body)
219 (and=> alternate retrans)))
220
221 ((lambda-case ((,req ,opt ,rest ,kw ,inits ,gensyms) ,body))
222 (make-lambda-case loc req opt rest kw
223 (map retrans inits) gensyms
224 (retrans body)
225 #f))
226
227 ((const ,exp)
228 (make-const loc exp))
229
230 ((seq ,head ,tail)
231 (make-seq loc (retrans head) (retrans tail)))
232
233 ;; Convenience.
234 ((begin . ,exps)
235 (list->seq loc (map retrans exps)))
236
237 ((let ,names ,gensyms ,vals ,body)
238 (make-let loc names gensyms (map retrans vals) (retrans body)))
239
240 ((letrec ,names ,gensyms ,vals ,body)
241 (make-letrec loc #f names gensyms (map retrans vals) (retrans body)))
242
243 ((letrec* ,names ,gensyms ,vals ,body)
244 (make-letrec loc #t names gensyms (map retrans vals) (retrans body)))
245
246 ((fix ,names ,gensyms ,vals ,body)
247 (make-fix loc names gensyms (map retrans vals) (retrans body)))
248
249 ((let-values ,exp ,body)
250 (make-let-values loc (retrans exp) (retrans body)))
251
252 ((dynwind ,winder ,pre ,body ,post ,unwinder)
253 (make-dynwind loc (retrans winder) (retrans pre)
254 (retrans body)
255 (retrans post) (retrans unwinder)))
256
257 ((dynlet ,fluids ,vals ,body)
258 (make-dynlet loc (map retrans fluids) (map retrans vals) (retrans body)))
259
260 ((dynref ,fluid)
261 (make-dynref loc (retrans fluid)))
262
263 ((dynset ,fluid ,exp)
264 (make-dynset loc (retrans fluid) (retrans exp)))
265
266 ((prompt ,tag ,body ,handler)
267 (make-prompt loc (retrans tag) (retrans body) (retrans handler)))
268
269 ((abort ,tag ,args ,tail)
270 (make-abort loc (retrans tag) (map retrans args) (retrans tail)))
271
272 (else
273 (error "unrecognized tree-il" exp)))))
274
275 (define (unparse-tree-il tree-il)
276 (record-case tree-il
277 ((<void>)
278 '(void))
279
280 ((<call> proc args)
281 `(call ,(unparse-tree-il proc) ,@(map unparse-tree-il args)))
282
283 ((<primcall> name args)
284 `(primcall ,name ,@(map unparse-tree-il args)))
285
286 ((<conditional> test consequent alternate)
287 `(if ,(unparse-tree-il test) ,(unparse-tree-il consequent) ,(unparse-tree-il alternate)))
288
289 ((<primitive-ref> name)
290 `(primitive ,name))
291
292 ((<lexical-ref> name gensym)
293 `(lexical ,name ,gensym))
294
295 ((<lexical-set> name gensym exp)
296 `(set! (lexical ,name ,gensym) ,(unparse-tree-il exp)))
297
298 ((<module-ref> mod name public?)
299 `(,(if public? '@ '@@) ,mod ,name))
300
301 ((<module-set> mod name public? exp)
302 `(set! (,(if public? '@ '@@) ,mod ,name) ,(unparse-tree-il exp)))
303
304 ((<toplevel-ref> name)
305 `(toplevel ,name))
306
307 ((<toplevel-set> name exp)
308 `(set! (toplevel ,name) ,(unparse-tree-il exp)))
309
310 ((<toplevel-define> name exp)
311 `(define ,name ,(unparse-tree-il exp)))
312
313 ((<lambda> meta body)
314 `(lambda ,meta ,(unparse-tree-il body)))
315
316 ((<lambda-case> req opt rest kw inits gensyms body alternate)
317 `(lambda-case ((,req ,opt ,rest ,kw ,(map unparse-tree-il inits) ,gensyms)
318 ,(unparse-tree-il body))
319 . ,(if alternate (list (unparse-tree-il alternate)) '())))
320
321 ((<const> exp)
322 `(const ,exp))
323
324 ((<seq> head tail)
325 `(seq ,(unparse-tree-il head) ,(unparse-tree-il tail)))
326
327 ((<let> names gensyms vals body)
328 `(let ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
329
330 ((<letrec> in-order? names gensyms vals body)
331 `(,(if in-order? 'letrec* 'letrec) ,names ,gensyms
332 ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
333
334 ((<fix> names gensyms vals body)
335 `(fix ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
336
337 ((<let-values> exp body)
338 `(let-values ,(unparse-tree-il exp) ,(unparse-tree-il body)))
339
340 ((<dynwind> winder pre body post unwinder)
341 `(dynwind ,(unparse-tree-il winder) ,(unparse-tree-il pre)
342 ,(unparse-tree-il body)
343 ,(unparse-tree-il post) ,(unparse-tree-il unwinder)))
344
345 ((<dynlet> fluids vals body)
346 `(dynlet ,(map unparse-tree-il fluids) ,(map unparse-tree-il vals)
347 ,(unparse-tree-il body)))
348
349 ((<dynref> fluid)
350 `(dynref ,(unparse-tree-il fluid)))
351
352 ((<dynset> fluid exp)
353 `(dynset ,(unparse-tree-il fluid) ,(unparse-tree-il exp)))
354
355 ((<prompt> tag body handler)
356 `(prompt ,(unparse-tree-il tag) ,(unparse-tree-il body) ,(unparse-tree-il handler)))
357
358 ((<abort> tag args tail)
359 `(abort ,(unparse-tree-il tag) ,(map unparse-tree-il args)
360 ,(unparse-tree-il tail)))))
361
362 (define* (tree-il->scheme e #:optional (env #f) (opts '()))
363 (values ((@ (language scheme decompile-tree-il)
364 decompile-tree-il)
365 e env opts)))
366
367 \f
368 (define (tree-il-fold leaf down up seed tree)
369 "Traverse TREE, calling LEAF on each leaf encountered, DOWN upon descent
370 into a sub-tree, and UP when leaving a sub-tree. Each of these procedures is
371 invoked as `(PROC TREE SEED)', where TREE is the sub-tree or leaf considered
372 and SEED is the current result, intially seeded with SEED.
373
374 This is an implementation of `foldts' as described by Andy Wingo in
375 ``Calls of fold to XML transformation''."
376 (let loop ((tree tree)
377 (result seed))
378 (if (or (null? tree) (pair? tree))
379 (fold loop result tree)
380 (record-case tree
381 ((<lexical-set> exp)
382 (up tree (loop exp (down tree result))))
383 ((<module-set> exp)
384 (up tree (loop exp (down tree result))))
385 ((<toplevel-set> exp)
386 (up tree (loop exp (down tree result))))
387 ((<toplevel-define> exp)
388 (up tree (loop exp (down tree result))))
389 ((<conditional> test consequent alternate)
390 (up tree (loop alternate
391 (loop consequent
392 (loop test (down tree result))))))
393 ((<call> proc args)
394 (up tree (loop (cons proc args) (down tree result))))
395 ((<primcall> name args)
396 (up tree (loop args (down tree result))))
397 ((<seq> head tail)
398 (up tree (loop tail (loop head (down tree result)))))
399 ((<lambda> body)
400 (up tree (loop body (down tree result))))
401 ((<lambda-case> inits body alternate)
402 (up tree (if alternate
403 (loop alternate
404 (loop body (loop inits (down tree result))))
405 (loop body (loop inits (down tree result))))))
406 ((<let> vals body)
407 (up tree (loop body
408 (loop vals
409 (down tree result)))))
410 ((<letrec> vals body)
411 (up tree (loop body
412 (loop vals
413 (down tree result)))))
414 ((<fix> vals body)
415 (up tree (loop body
416 (loop vals
417 (down tree result)))))
418 ((<let-values> exp body)
419 (up tree (loop body (loop exp (down tree result)))))
420 ((<dynwind> winder pre body post unwinder)
421 (up tree (loop unwinder
422 (loop post
423 (loop body
424 (loop pre
425 (loop winder
426 (down tree result))))))))
427 ((<dynlet> fluids vals body)
428 (up tree (loop body
429 (loop vals
430 (loop fluids (down tree result))))))
431 ((<dynref> fluid)
432 (up tree (loop fluid (down tree result))))
433 ((<dynset> fluid exp)
434 (up tree (loop exp (loop fluid (down tree result)))))
435 ((<prompt> tag body handler)
436 (up tree
437 (loop tag (loop body (loop handler
438 (down tree result))))))
439 ((<abort> tag args tail)
440 (up tree (loop tail (loop args (loop tag (down tree result))))))
441 (else
442 (leaf tree result))))))
443
444
445 (define-syntax-rule (make-tree-il-folder seed ...)
446 (lambda (tree down up seed ...)
447 (define (fold-values proc exps seed ...)
448 (if (null? exps)
449 (values seed ...)
450 (let-values (((seed ...) (proc (car exps) seed ...)))
451 (fold-values proc (cdr exps) seed ...))))
452 (let foldts ((tree tree) (seed seed) ...)
453 (let*-values
454 (((seed ...) (down tree seed ...))
455 ((seed ...)
456 (record-case tree
457 ((<lexical-set> exp)
458 (foldts exp seed ...))
459 ((<module-set> exp)
460 (foldts exp seed ...))
461 ((<toplevel-set> exp)
462 (foldts exp seed ...))
463 ((<toplevel-define> exp)
464 (foldts exp seed ...))
465 ((<conditional> test consequent alternate)
466 (let*-values (((seed ...) (foldts test seed ...))
467 ((seed ...) (foldts consequent seed ...)))
468 (foldts alternate seed ...)))
469 ((<call> proc args)
470 (let-values (((seed ...) (foldts proc seed ...)))
471 (fold-values foldts args seed ...)))
472 ((<primcall> name args)
473 (fold-values foldts args seed ...))
474 ((<seq> head tail)
475 (let-values (((seed ...) (foldts head seed ...)))
476 (foldts tail seed ...)))
477 ((<lambda> body)
478 (foldts body seed ...))
479 ((<lambda-case> inits body alternate)
480 (let-values (((seed ...) (fold-values foldts inits seed ...)))
481 (if alternate
482 (let-values (((seed ...) (foldts body seed ...)))
483 (foldts alternate seed ...))
484 (foldts body seed ...))))
485 ((<let> vals body)
486 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
487 (foldts body seed ...)))
488 ((<letrec> vals body)
489 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
490 (foldts body seed ...)))
491 ((<fix> vals body)
492 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
493 (foldts body seed ...)))
494 ((<let-values> exp body)
495 (let*-values (((seed ...) (foldts exp seed ...)))
496 (foldts body seed ...)))
497 ((<dynwind> winder pre body post unwinder)
498 (let*-values (((seed ...) (foldts winder seed ...))
499 ((seed ...) (foldts pre seed ...))
500 ((seed ...) (foldts body seed ...))
501 ((seed ...) (foldts post seed ...)))
502 (foldts unwinder seed ...)))
503 ((<dynlet> fluids vals body)
504 (let*-values (((seed ...) (fold-values foldts fluids seed ...))
505 ((seed ...) (fold-values foldts vals seed ...)))
506 (foldts body seed ...)))
507 ((<dynref> fluid)
508 (foldts fluid seed ...))
509 ((<dynset> fluid exp)
510 (let*-values (((seed ...) (foldts fluid seed ...)))
511 (foldts exp seed ...)))
512 ((<prompt> tag body handler)
513 (let*-values (((seed ...) (foldts tag seed ...))
514 ((seed ...) (foldts body seed ...)))
515 (foldts handler seed ...)))
516 ((<abort> tag args tail)
517 (let*-values (((seed ...) (foldts tag seed ...))
518 ((seed ...) (fold-values foldts args seed ...)))
519 (foldts tail seed ...)))
520 (else
521 (values seed ...)))))
522 (up tree seed ...)))))
523
524 (define (post-order! f x)
525 (let lp ((x x))
526 (record-case x
527 ((<call> proc args)
528 (set! (call-proc x) (lp proc))
529 (set! (call-args x) (map lp args)))
530
531 ((<primcall> name args)
532 (set! (primcall-args x) (map lp args)))
533
534 ((<conditional> test consequent alternate)
535 (set! (conditional-test x) (lp test))
536 (set! (conditional-consequent x) (lp consequent))
537 (set! (conditional-alternate x) (lp alternate)))
538
539 ((<lexical-set> name gensym exp)
540 (set! (lexical-set-exp x) (lp exp)))
541
542 ((<module-set> mod name public? exp)
543 (set! (module-set-exp x) (lp exp)))
544
545 ((<toplevel-set> name exp)
546 (set! (toplevel-set-exp x) (lp exp)))
547
548 ((<toplevel-define> name exp)
549 (set! (toplevel-define-exp x) (lp exp)))
550
551 ((<lambda> body)
552 (set! (lambda-body x) (lp body)))
553
554 ((<lambda-case> inits body alternate)
555 (set! inits (map lp inits))
556 (set! (lambda-case-body x) (lp body))
557 (if alternate
558 (set! (lambda-case-alternate x) (lp alternate))))
559
560 ((<seq> head tail)
561 (set! (seq-head x) (lp head))
562 (set! (seq-tail x) (lp tail)))
563
564 ((<let> gensyms vals body)
565 (set! (let-vals x) (map lp vals))
566 (set! (let-body x) (lp body)))
567
568 ((<letrec> gensyms vals body)
569 (set! (letrec-vals x) (map lp vals))
570 (set! (letrec-body x) (lp body)))
571
572 ((<fix> gensyms vals body)
573 (set! (fix-vals x) (map lp vals))
574 (set! (fix-body x) (lp body)))
575
576 ((<let-values> exp body)
577 (set! (let-values-exp x) (lp exp))
578 (set! (let-values-body x) (lp body)))
579
580 ((<dynwind> winder pre body post unwinder)
581 (set! (dynwind-winder x) (lp winder))
582 (set! (dynwind-pre x) (lp pre))
583 (set! (dynwind-body x) (lp body))
584 (set! (dynwind-post x) (lp post))
585 (set! (dynwind-unwinder x) (lp unwinder)))
586
587 ((<dynlet> fluids vals body)
588 (set! (dynlet-fluids x) (map lp fluids))
589 (set! (dynlet-vals x) (map lp vals))
590 (set! (dynlet-body x) (lp body)))
591
592 ((<dynref> fluid)
593 (set! (dynref-fluid x) (lp fluid)))
594
595 ((<dynset> fluid exp)
596 (set! (dynset-fluid x) (lp fluid))
597 (set! (dynset-exp x) (lp exp)))
598
599 ((<prompt> tag body handler)
600 (set! (prompt-tag x) (lp tag))
601 (set! (prompt-body x) (lp body))
602 (set! (prompt-handler x) (lp handler)))
603
604 ((<abort> tag args tail)
605 (set! (abort-tag x) (lp tag))
606 (set! (abort-args x) (map lp args))
607 (set! (abort-tail x) (lp tail)))
608
609 (else #f))
610
611 (or (f x) x)))
612
613 (define (pre-order! f x)
614 (let lp ((x x))
615 (let ((x (or (f x) x)))
616 (record-case x
617 ((<call> proc args)
618 (set! (call-proc x) (lp proc))
619 (set! (call-args x) (map lp args)))
620
621 ((<primcall> name args)
622 (set! (primcall-args x) (map lp args)))
623
624 ((<conditional> test consequent alternate)
625 (set! (conditional-test x) (lp test))
626 (set! (conditional-consequent x) (lp consequent))
627 (set! (conditional-alternate x) (lp alternate)))
628
629 ((<lexical-set> exp)
630 (set! (lexical-set-exp x) (lp exp)))
631
632 ((<module-set> exp)
633 (set! (module-set-exp x) (lp exp)))
634
635 ((<toplevel-set> exp)
636 (set! (toplevel-set-exp x) (lp exp)))
637
638 ((<toplevel-define> exp)
639 (set! (toplevel-define-exp x) (lp exp)))
640
641 ((<lambda> body)
642 (set! (lambda-body x) (lp body)))
643
644 ((<lambda-case> inits body alternate)
645 (set! inits (map lp inits))
646 (set! (lambda-case-body x) (lp body))
647 (if alternate (set! (lambda-case-alternate x) (lp alternate))))
648
649 ((<seq> head tail)
650 (set! (seq-head x) (lp head))
651 (set! (seq-tail x) (lp tail)))
652
653 ((<let> vals body)
654 (set! (let-vals x) (map lp vals))
655 (set! (let-body x) (lp body)))
656
657 ((<letrec> vals body)
658 (set! (letrec-vals x) (map lp vals))
659 (set! (letrec-body x) (lp body)))
660
661 ((<fix> vals body)
662 (set! (fix-vals x) (map lp vals))
663 (set! (fix-body x) (lp body)))
664
665 ((<let-values> exp body)
666 (set! (let-values-exp x) (lp exp))
667 (set! (let-values-body x) (lp body)))
668
669 ((<dynwind> winder pre body post unwinder)
670 (set! (dynwind-winder x) (lp winder))
671 (set! (dynwind-pre x) (lp pre))
672 (set! (dynwind-body x) (lp body))
673 (set! (dynwind-post x) (lp post))
674 (set! (dynwind-unwinder x) (lp unwinder)))
675
676 ((<dynlet> fluids vals body)
677 (set! (dynlet-fluids x) (map lp fluids))
678 (set! (dynlet-vals x) (map lp vals))
679 (set! (dynlet-body x) (lp body)))
680
681 ((<dynref> fluid)
682 (set! (dynref-fluid x) (lp fluid)))
683
684 ((<dynset> fluid exp)
685 (set! (dynset-fluid x) (lp fluid))
686 (set! (dynset-exp x) (lp exp)))
687
688 ((<prompt> tag body handler)
689 (set! (prompt-tag x) (lp tag))
690 (set! (prompt-body x) (lp body))
691 (set! (prompt-handler x) (lp handler)))
692
693 ((<abort> tag args tail)
694 (set! (abort-tag x) (lp tag))
695 (set! (abort-args x) (map lp args))
696 (set! (abort-tail x) (lp tail)))
697
698 (else #f))
699 x)))
700
701 ;; FIXME: We should have a better primitive than this.
702 (define (struct-nfields x)
703 (/ (string-length (symbol->string (struct-layout x))) 2))
704
705 (define (tree-il=? a b)
706 (cond
707 ((struct? a)
708 (and (struct? b)
709 (eq? (struct-vtable a) (struct-vtable b))
710 ;; Assume that all structs are tree-il, so we skip over the
711 ;; src slot.
712 (let lp ((n (1- (struct-nfields a))))
713 (or (zero? n)
714 (and (tree-il=? (struct-ref a n) (struct-ref b n))
715 (lp (1- n)))))))
716 ((pair? a)
717 (and (pair? b)
718 (tree-il=? (car a) (car b))
719 (tree-il=? (cdr a) (cdr b))))
720 (else
721 (equal? a b))))
722
723 (define-syntax hash-bits
724 (make-variable-transformer
725 (lambda (x)
726 (syntax-case x ()
727 (var
728 (identifier? #'var)
729 (logcount most-positive-fixnum))))))
730
731 (define (tree-il-hash exp)
732 (let ((hash-depth 4)
733 (hash-width 3))
734 (define (hash-exp exp depth)
735 (define (rotate x bits)
736 (logior (ash x (- bits))
737 (ash (logand x (1- (ash 1 bits))) (- hash-bits bits))))
738 (define (mix h1 h2)
739 (logxor h1 (rotate h2 8)))
740 (define (hash-struct s)
741 (let ((len (struct-nfields s))
742 (h (hashq (struct-vtable s) most-positive-fixnum)))
743 (if (zero? depth)
744 h
745 (let lp ((i (max (- len hash-width) 1)) (h h))
746 (if (< i len)
747 (lp (1+ i) (mix (hash-exp (struct-ref s i) (1+ depth)) h))
748 h)))))
749 (define (hash-list l)
750 (let ((h (hashq 'list most-positive-fixnum)))
751 (if (zero? depth)
752 h
753 (let lp ((l l) (width 0) (h h))
754 (if (< width hash-width)
755 (lp (cdr l) (1+ width)
756 (mix (hash-exp (car l) (1+ depth)) h))
757 h)))))
758 (cond
759 ((struct? exp) (hash-struct exp))
760 ((list? exp) (hash-list exp))
761 (else (hash exp most-positive-fixnum))))
762
763 (hash-exp exp 0)))