1 ;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
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.
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.
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
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)
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
70 (define (print-tree-il exp port)
71 (format port "#<tree-il ~S>" (unparse-tree-il exp)))
73 (define-syntax borrow-core-vtables
77 (let lp ((n 0) (out '()))
78 (if (< n (vector-length %expanded-vtables))
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)))
84 (lambda (f) (datum->syntax x f))
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)
91 #`(define (#,ctor #,@sfields)
92 (make-struct #,type 0 #,@sfields))
95 (eq? (struct-vtable x) #,type)))
96 #`(struct-set! #,type vtable-index-printer
99 (vector-ref %expanded-vtables #,n))
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))))
112 #`(begin #,@(reverse out))))))))
114 (borrow-core-vtables)
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)
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)
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)
142 (<prompt> tag body handler)
143 (<abort> tag args tail))
148 (define (list->seq loc exps)
149 (if (null? (cdr exps))
151 (make-seq loc (car exps) (list->seq #f (cdr exps)))))
157 (let ((props (source-properties x)))
158 (and (pair? props) props))))
160 (define (parse-tree-il exp)
161 (let ((loc (location exp))
162 (retrans (lambda (x) (parse-tree-il x))))
167 ((call ,proc . ,args)
168 (make-call loc (retrans proc) (map retrans args)))
170 ((primcall ,name . ,args)
171 (make-primcall loc name (map retrans args)))
173 ((if ,test ,consequent ,alternate)
174 (make-conditional loc (retrans test) (retrans consequent) (retrans alternate)))
176 ((primitive ,name) (guard (symbol? name))
177 (make-primitive-ref loc name))
179 ((lexical ,name) (guard (symbol? name))
180 (make-lexical-ref loc name name))
182 ((lexical ,name ,sym) (guard (symbol? name) (symbol? sym))
183 (make-lexical-ref loc name sym))
185 ((set! (lexical ,name) ,exp) (guard (symbol? name))
186 (make-lexical-set loc name name (retrans exp)))
188 ((set! (lexical ,name ,sym) ,exp) (guard (symbol? name) (symbol? sym))
189 (make-lexical-set loc name sym (retrans exp)))
191 ((@ ,mod ,name) (guard (and-map symbol? mod) (symbol? name))
192 (make-module-ref loc mod name #t))
194 ((set! (@ ,mod ,name) ,exp) (guard (and-map symbol? mod) (symbol? name))
195 (make-module-set loc mod name #t (retrans exp)))
197 ((@@ ,mod ,name) (guard (and-map symbol? mod) (symbol? name))
198 (make-module-ref loc mod name #f))
200 ((set! (@@ ,mod ,name) ,exp) (guard (and-map symbol? mod) (symbol? name))
201 (make-module-set loc mod name #f (retrans exp)))
203 ((toplevel ,name) (guard (symbol? name))
204 (make-toplevel-ref loc name))
206 ((set! (toplevel ,name) ,exp) (guard (symbol? name))
207 (make-toplevel-set loc name (retrans exp)))
209 ((define ,name ,exp) (guard (symbol? name))
210 (make-toplevel-define loc name (retrans exp)))
212 ((lambda ,meta ,body)
213 (make-lambda loc meta (retrans body)))
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
219 (and=> alternate retrans)))
221 ((lambda-case ((,req ,opt ,rest ,kw ,inits ,gensyms) ,body))
222 (make-lambda-case loc req opt rest kw
223 (map retrans inits) gensyms
228 (make-const loc exp))
231 (make-seq loc (retrans head) (retrans tail)))
235 (list->seq loc (map retrans exps)))
237 ((let ,names ,gensyms ,vals ,body)
238 (make-let loc names gensyms (map retrans vals) (retrans body)))
240 ((letrec ,names ,gensyms ,vals ,body)
241 (make-letrec loc #f names gensyms (map retrans vals) (retrans body)))
243 ((letrec* ,names ,gensyms ,vals ,body)
244 (make-letrec loc #t names gensyms (map retrans vals) (retrans body)))
246 ((fix ,names ,gensyms ,vals ,body)
247 (make-fix loc names gensyms (map retrans vals) (retrans body)))
249 ((let-values ,exp ,body)
250 (make-let-values loc (retrans exp) (retrans body)))
252 ((dynwind ,winder ,pre ,body ,post ,unwinder)
253 (make-dynwind loc (retrans winder) (retrans pre)
255 (retrans post) (retrans unwinder)))
257 ((dynlet ,fluids ,vals ,body)
258 (make-dynlet loc (map retrans fluids) (map retrans vals) (retrans body)))
261 (make-dynref loc (retrans fluid)))
263 ((dynset ,fluid ,exp)
264 (make-dynset loc (retrans fluid) (retrans exp)))
266 ((prompt ,tag ,body ,handler)
267 (make-prompt loc (retrans tag) (retrans body) (retrans handler)))
269 ((abort ,tag ,args ,tail)
270 (make-abort loc (retrans tag) (map retrans args) (retrans tail)))
273 (error "unrecognized tree-il" exp)))))
275 (define (unparse-tree-il tree-il)
281 `(call ,(unparse-tree-il proc) ,@(map unparse-tree-il args)))
283 ((<primcall> name args)
284 `(primcall ,name ,@(map unparse-tree-il args)))
286 ((<conditional> test consequent alternate)
287 `(if ,(unparse-tree-il test) ,(unparse-tree-il consequent) ,(unparse-tree-il alternate)))
289 ((<primitive-ref> name)
292 ((<lexical-ref> name gensym)
293 `(lexical ,name ,gensym))
295 ((<lexical-set> name gensym exp)
296 `(set! (lexical ,name ,gensym) ,(unparse-tree-il exp)))
298 ((<module-ref> mod name public?)
299 `(,(if public? '@ '@@) ,mod ,name))
301 ((<module-set> mod name public? exp)
302 `(set! (,(if public? '@ '@@) ,mod ,name) ,(unparse-tree-il exp)))
304 ((<toplevel-ref> name)
307 ((<toplevel-set> name exp)
308 `(set! (toplevel ,name) ,(unparse-tree-il exp)))
310 ((<toplevel-define> name exp)
311 `(define ,name ,(unparse-tree-il exp)))
313 ((<lambda> meta body)
315 `(lambda ,meta ,(unparse-tree-il body))
316 `(lambda ,meta (lambda-case))))
318 ((<lambda-case> req opt rest kw inits gensyms body alternate)
319 `(lambda-case ((,req ,opt ,rest ,kw ,(map unparse-tree-il inits) ,gensyms)
320 ,(unparse-tree-il body))
321 . ,(if alternate (list (unparse-tree-il alternate)) '())))
327 `(seq ,(unparse-tree-il head) ,(unparse-tree-il tail)))
329 ((<let> names gensyms vals body)
330 `(let ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
332 ((<letrec> in-order? names gensyms vals body)
333 `(,(if in-order? 'letrec* 'letrec) ,names ,gensyms
334 ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
336 ((<fix> names gensyms vals body)
337 `(fix ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
339 ((<let-values> exp body)
340 `(let-values ,(unparse-tree-il exp) ,(unparse-tree-il body)))
342 ((<dynwind> winder pre body post unwinder)
343 `(dynwind ,(unparse-tree-il winder) ,(unparse-tree-il pre)
344 ,(unparse-tree-il body)
345 ,(unparse-tree-il post) ,(unparse-tree-il unwinder)))
347 ((<dynlet> fluids vals body)
348 `(dynlet ,(map unparse-tree-il fluids) ,(map unparse-tree-il vals)
349 ,(unparse-tree-il body)))
352 `(dynref ,(unparse-tree-il fluid)))
354 ((<dynset> fluid exp)
355 `(dynset ,(unparse-tree-il fluid) ,(unparse-tree-il exp)))
357 ((<prompt> tag body handler)
358 `(prompt ,(unparse-tree-il tag) ,(unparse-tree-il body) ,(unparse-tree-il handler)))
360 ((<abort> tag args tail)
361 `(abort ,(unparse-tree-il tag) ,(map unparse-tree-il args)
362 ,(unparse-tree-il tail)))))
364 (define* (tree-il->scheme e #:optional (env #f) (opts '()))
365 (values ((@ (language scheme decompile-tree-il)
370 (define (tree-il-fold leaf down up seed tree)
371 "Traverse TREE, calling LEAF on each leaf encountered, DOWN upon descent
372 into a sub-tree, and UP when leaving a sub-tree. Each of these procedures is
373 invoked as `(PROC TREE SEED)', where TREE is the sub-tree or leaf considered
374 and SEED is the current result, intially seeded with SEED.
376 This is an implementation of `foldts' as described by Andy Wingo in
377 ``Calls of fold to XML transformation''."
378 (let loop ((tree tree)
380 (if (or (null? tree) (pair? tree))
381 (fold loop result tree)
384 (up tree (loop exp (down tree result))))
386 (up tree (loop exp (down tree result))))
387 ((<toplevel-set> exp)
388 (up tree (loop exp (down tree result))))
389 ((<toplevel-define> exp)
390 (up tree (loop exp (down tree result))))
391 ((<conditional> test consequent alternate)
392 (up tree (loop alternate
394 (loop test (down tree result))))))
396 (up tree (loop (cons proc args) (down tree result))))
397 ((<primcall> name args)
398 (up tree (loop args (down tree result))))
400 (up tree (loop tail (loop head (down tree result)))))
402 (let ((result (down tree result)))
407 ((<lambda-case> inits body alternate)
408 (up tree (if alternate
410 (loop body (loop inits (down tree result))))
411 (loop body (loop inits (down tree result))))))
415 (down tree result)))))
416 ((<letrec> vals body)
419 (down tree result)))))
423 (down tree result)))))
424 ((<let-values> exp body)
425 (up tree (loop body (loop exp (down tree result)))))
426 ((<dynwind> winder pre body post unwinder)
427 (up tree (loop unwinder
432 (down tree result))))))))
433 ((<dynlet> fluids vals body)
436 (loop fluids (down tree result))))))
438 (up tree (loop fluid (down tree result))))
439 ((<dynset> fluid exp)
440 (up tree (loop exp (loop fluid (down tree result)))))
441 ((<prompt> tag body handler)
443 (loop tag (loop body (loop handler
444 (down tree result))))))
445 ((<abort> tag args tail)
446 (up tree (loop tail (loop args (loop tag (down tree result))))))
448 (leaf tree result))))))
451 (define-syntax-rule (make-tree-il-folder seed ...)
452 (lambda (tree down up seed ...)
453 (define (fold-values proc exps seed ...)
456 (let-values (((seed ...) (proc (car exps) seed ...)))
457 (fold-values proc (cdr exps) seed ...))))
458 (let foldts ((tree tree) (seed seed) ...)
460 (((seed ...) (down tree seed ...))
464 (foldts exp seed ...))
466 (foldts exp seed ...))
467 ((<toplevel-set> exp)
468 (foldts exp seed ...))
469 ((<toplevel-define> exp)
470 (foldts exp seed ...))
471 ((<conditional> test consequent alternate)
472 (let*-values (((seed ...) (foldts test seed ...))
473 ((seed ...) (foldts consequent seed ...)))
474 (foldts alternate seed ...)))
476 (let-values (((seed ...) (foldts proc seed ...)))
477 (fold-values foldts args seed ...)))
478 ((<primcall> name args)
479 (fold-values foldts args seed ...))
481 (let-values (((seed ...) (foldts head seed ...)))
482 (foldts tail seed ...)))
485 (foldts body seed ...)
487 ((<lambda-case> inits body alternate)
488 (let-values (((seed ...) (fold-values foldts inits seed ...)))
490 (let-values (((seed ...) (foldts body seed ...)))
491 (foldts alternate seed ...))
492 (foldts body seed ...))))
494 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
495 (foldts body seed ...)))
496 ((<letrec> vals body)
497 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
498 (foldts body seed ...)))
500 (let*-values (((seed ...) (fold-values foldts vals seed ...)))
501 (foldts body seed ...)))
502 ((<let-values> exp body)
503 (let*-values (((seed ...) (foldts exp seed ...)))
504 (foldts body seed ...)))
505 ((<dynwind> winder pre body post unwinder)
506 (let*-values (((seed ...) (foldts winder seed ...))
507 ((seed ...) (foldts pre seed ...))
508 ((seed ...) (foldts body seed ...))
509 ((seed ...) (foldts post seed ...)))
510 (foldts unwinder seed ...)))
511 ((<dynlet> fluids vals body)
512 (let*-values (((seed ...) (fold-values foldts fluids seed ...))
513 ((seed ...) (fold-values foldts vals seed ...)))
514 (foldts body seed ...)))
516 (foldts fluid seed ...))
517 ((<dynset> fluid exp)
518 (let*-values (((seed ...) (foldts fluid seed ...)))
519 (foldts exp seed ...)))
520 ((<prompt> tag body handler)
521 (let*-values (((seed ...) (foldts tag seed ...))
522 ((seed ...) (foldts body seed ...)))
523 (foldts handler seed ...)))
524 ((<abort> tag args tail)
525 (let*-values (((seed ...) (foldts tag seed ...))
526 ((seed ...) (fold-values foldts args seed ...)))
527 (foldts tail seed ...)))
529 (values seed ...)))))
530 (up tree seed ...)))))
532 (define (pre-post-order pre post x)
540 (make-const src exp))
542 ((<primitive-ref> src name)
543 (make-primitive-ref src name))
545 ((<lexical-ref> src name gensym)
546 (make-lexical-ref src name gensym))
548 ((<lexical-set> src name gensym exp)
549 (make-lexical-set src name gensym (lp exp)))
551 ((<module-ref> src mod name public?)
552 (make-module-ref src mod name public?))
554 ((<module-set> src mod name public? exp)
555 (make-module-set src mod name public? (lp exp)))
557 ((<toplevel-ref> src name)
558 (make-toplevel-ref src name))
560 ((<toplevel-set> src name exp)
561 (make-toplevel-set src name (lp exp)))
563 ((<toplevel-define> src name exp)
564 (make-toplevel-define src name (lp exp)))
566 ((<conditional> src test consequent alternate)
567 (make-conditional src (lp test) (lp consequent) (lp alternate)))
569 ((<call> src proc args)
570 (make-call src (lp proc) (map lp args)))
572 ((<primcall> src name args)
573 (make-primcall src name (map lp args)))
575 ((<seq> src head tail)
576 (make-seq src (lp head) (lp tail)))
578 ((<lambda> src meta body)
579 (make-lambda src meta (and body (lp body))))
581 ((<lambda-case> src req opt rest kw inits gensyms body alternate)
582 (make-lambda-case src req opt rest kw (map lp inits) gensyms (lp body)
583 (and alternate (lp alternate))))
585 ((<let> src names gensyms vals body)
586 (make-let src names gensyms (map lp vals) (lp body)))
588 ((<letrec> src in-order? names gensyms vals body)
589 (make-letrec src in-order? names gensyms (map lp vals) (lp body)))
591 ((<fix> src names gensyms vals body)
592 (make-fix src names gensyms (map lp vals) (lp body)))
594 ((<let-values> src exp body)
595 (make-let-values src (lp exp) (lp body)))
597 ((<dynwind> src winder pre body post unwinder)
599 (lp winder) (lp pre) (lp body) (lp post) (lp unwinder)))
601 ((<dynlet> src fluids vals body)
602 (make-dynlet src (map lp fluids) (map lp vals) (lp body)))
604 ((<dynref> src fluid)
605 (make-dynref src (lp fluid)))
607 ((<dynset> src fluid exp)
608 (make-dynset src (lp fluid) (lp exp)))
610 ((<prompt> src tag body handler)
611 (make-prompt src (lp tag) (lp body) (lp handler)))
613 ((<abort> src tag args tail)
614 (make-abort src (lp tag) (map lp args) (lp tail)))))))
616 (define (post-order f x)
617 (pre-post-order (lambda (x) x) f x))
619 (define (pre-order f x)
620 (pre-post-order f (lambda (x) x) x))
622 ;; FIXME: We should have a better primitive than this.
623 (define (struct-nfields x)
624 (/ (string-length (symbol->string (struct-layout x))) 2))
626 (define (tree-il=? a b)
630 (eq? (struct-vtable a) (struct-vtable b))
631 ;; Assume that all structs are tree-il, so we skip over the
633 (let lp ((n (1- (struct-nfields a))))
635 (and (tree-il=? (struct-ref a n) (struct-ref b n))
639 (tree-il=? (car a) (car b))
640 (tree-il=? (cdr a) (cdr b))))
644 (define-syntax hash-bits
645 (make-variable-transformer
650 (logcount most-positive-fixnum))))))
652 (define (tree-il-hash exp)
655 (define (hash-exp exp depth)
656 (define (rotate x bits)
657 (logior (ash x (- bits))
658 (ash (logand x (1- (ash 1 bits))) (- hash-bits bits))))
660 (logxor h1 (rotate h2 8)))
661 (define (hash-struct s)
662 (let ((len (struct-nfields s))
663 (h (hashq (struct-vtable s) most-positive-fixnum)))
666 (let lp ((i (max (- len hash-width) 1)) (h h))
668 (lp (1+ i) (mix (hash-exp (struct-ref s i) (1+ depth)) h))
670 (define (hash-list l)
671 (let ((h (hashq 'list most-positive-fixnum)))
674 (let lp ((l l) (width 0) (h h))
675 (if (< width hash-width)
676 (lp (cdr l) (1+ width)
677 (mix (hash-exp (car l) (1+ depth)) h))
680 ((struct? exp) (hash-struct exp))
681 ((list? exp) (hash-list exp))
682 (else (hash exp most-positive-fixnum))))