X-Git-Url: https://git.hcoop.net/bpt/guile.git/blobdiff_plain/19113f1ca7a747de06d7b43c6c1eca4cd58d05e5..f4af36aca47f7d0653b997986e8be9894bbd87ff:/module/language/tree-il.scm diff --git a/module/language/tree-il.scm b/module/language/tree-il.scm index aa00b381e..dcd03466a 100644 --- a/module/language/tree-il.scm +++ b/module/language/tree-il.scm @@ -1,4 +1,4 @@ -;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. +;;;; Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc. ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ (define-module (language tree-il) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) - #:use-module (system base pmatch) + #:use-module (ice-9 match) #:use-module (system base syntax) #:export (tree-il-src @@ -34,10 +34,12 @@ toplevel-set? make-toplevel-set toplevel-set-src toplevel-set-name toplevel-set-exp toplevel-define? make-toplevel-define toplevel-define-src toplevel-define-name toplevel-define-exp conditional? make-conditional conditional-src conditional-test conditional-consequent conditional-alternate - application? make-application application-src application-proc application-args - sequence? make-sequence sequence-src sequence-exps + call? make-call call-src call-proc call-args + primcall? make-primcall primcall-src primcall-name primcall-args + seq? make-seq seq-src seq-head seq-tail lambda? make-lambda lambda-src lambda-meta lambda-body lambda-case? make-lambda-case lambda-case-src + ;; idea: arity lambda-case-req lambda-case-opt lambda-case-rest lambda-case-kw lambda-case-inits lambda-case-gensyms lambda-case-body lambda-case-alternate @@ -45,21 +47,19 @@ letrec? make-letrec letrec-src letrec-in-order? letrec-names letrec-gensyms letrec-vals letrec-body fix? make-fix fix-src fix-names fix-gensyms fix-vals fix-body let-values? make-let-values let-values-src let-values-exp let-values-body - dynwind? make-dynwind dynwind-src dynwind-winder dynwind-body dynwind-unwinder - dynlet? make-dynlet dynlet-src dynlet-fluids dynlet-vals dynlet-body - dynref? make-dynref dynref-src dynref-fluid - dynset? make-dynset dynset-src dynset-fluid dynset-exp - prompt? make-prompt prompt-src prompt-tag prompt-body prompt-handler + prompt? make-prompt prompt-src prompt-escape-only? prompt-tag prompt-body prompt-handler abort? make-abort abort-src abort-tag abort-args abort-tail + list->seq + parse-tree-il unparse-tree-il tree-il->scheme tree-il-fold make-tree-il-folder - post-order! - pre-order! + post-order + pre-order tree-il=? tree-il-hash)) @@ -121,25 +121,30 @@ ;; ( name exp) ;; ( name exp) ;; ( test consequent alternate) - ;; ( proc args) - ;; ( exps) + ;; ( proc args) + ;; ( name args) + ;; ( head tail) ;; ( meta body) ;; ( req opt rest kw inits gensyms body alternate) ;; ( names gensyms vals body) ;; ( in-order? names gensyms vals body) - ;; ( fluids vals body) (define-type ( #:common-slots (src) #:printer print-tree-il) ( names gensyms vals body) ( exp body) - ( winder body unwinder) - ( fluid) - ( fluid exp) - ( tag body handler) + ( escape-only? tag body handler) ( tag args tail)) +;; A helper. +(define (list->seq loc exps) + (if (null? (cdr exps)) + (car exps) + (make-seq loc (car exps) (list->seq #f (cdr exps))))) + + + (define (location x) (and (pair? x) (let ((props (source-properties x))) @@ -148,191 +153,181 @@ (define (parse-tree-il exp) (let ((loc (location exp)) (retrans (lambda (x) (parse-tree-il x)))) - (pmatch exp - ((void) + (match exp + (('void) (make-void loc)) - ((apply ,proc . ,args) - (make-application loc (retrans proc) (map retrans args))) + (('call proc . args) + (make-call loc (retrans proc) (map retrans args))) + + (('primcall name . args) + (make-primcall loc name (map retrans args))) - ((if ,test ,consequent ,alternate) + (('if test consequent alternate) (make-conditional loc (retrans test) (retrans consequent) (retrans alternate))) - ((primitive ,name) (guard (symbol? name)) + (('primitive (and name (? symbol?))) (make-primitive-ref loc name)) - ((lexical ,name) (guard (symbol? name)) + (('lexical (and name (? symbol?))) (make-lexical-ref loc name name)) - ((lexical ,name ,sym) (guard (symbol? name) (symbol? sym)) + (('lexical (and name (? symbol?)) (and sym (? symbol?))) (make-lexical-ref loc name sym)) - ((set! (lexical ,name) ,exp) (guard (symbol? name)) + (('set! ('lexical (and name (? symbol?))) exp) (make-lexical-set loc name name (retrans exp))) - ((set! (lexical ,name ,sym) ,exp) (guard (symbol? name) (symbol? sym)) + (('set! ('lexical (and name (? symbol?)) (and sym (? symbol?))) exp) (make-lexical-set loc name sym (retrans exp))) - ((@ ,mod ,name) (guard (and-map symbol? mod) (symbol? name)) + (('@ ((and mod (? symbol?)) ...) (and name (? symbol?))) (make-module-ref loc mod name #t)) - ((set! (@ ,mod ,name) ,exp) (guard (and-map symbol? mod) (symbol? name)) + (('set! ('@ ((and mod (? symbol?)) ...) (and name (? symbol?))) exp) (make-module-set loc mod name #t (retrans exp))) - ((@@ ,mod ,name) (guard (and-map symbol? mod) (symbol? name)) + (('@@ ((and mod (? symbol?)) ...) (and name (? symbol?))) (make-module-ref loc mod name #f)) - ((set! (@@ ,mod ,name) ,exp) (guard (and-map symbol? mod) (symbol? name)) + (('set! ('@@ ((and mod (? symbol?)) ...) (and name (? symbol?))) exp) (make-module-set loc mod name #f (retrans exp))) - ((toplevel ,name) (guard (symbol? name)) + (('toplevel (and name (? symbol?))) (make-toplevel-ref loc name)) - ((set! (toplevel ,name) ,exp) (guard (symbol? name)) + (('set! ('toplevel (and name (? symbol?))) exp) (make-toplevel-set loc name (retrans exp))) - ((define ,name ,exp) (guard (symbol? name)) + (('define (and name (? symbol?)) exp) (make-toplevel-define loc name (retrans exp))) - ((lambda ,meta ,body) + (('lambda meta body) (make-lambda loc meta (retrans body))) - ((lambda-case ((,req ,opt ,rest ,kw ,inits ,gensyms) ,body) ,alternate) + (('lambda-case ((req opt rest kw inits gensyms) body) alternate) (make-lambda-case loc req opt rest kw (map retrans inits) gensyms (retrans body) (and=> alternate retrans))) - ((lambda-case ((,req ,opt ,rest ,kw ,inits ,gensyms) ,body)) + (('lambda-case ((req opt rest kw inits gensyms) body)) (make-lambda-case loc req opt rest kw (map retrans inits) gensyms (retrans body) #f)) - ((const ,exp) + (('const exp) (make-const loc exp)) - ((begin . ,exps) - (make-sequence loc (map retrans exps))) + (('seq head tail) + (make-seq loc (retrans head) (retrans tail))) + + ;; Convenience. + (('begin . exps) + (list->seq loc (map retrans exps))) - ((let ,names ,gensyms ,vals ,body) + (('let names gensyms vals body) (make-let loc names gensyms (map retrans vals) (retrans body))) - ((letrec ,names ,gensyms ,vals ,body) + (('letrec names gensyms vals body) (make-letrec loc #f names gensyms (map retrans vals) (retrans body))) - ((letrec* ,names ,gensyms ,vals ,body) + (('letrec* names gensyms vals body) (make-letrec loc #t names gensyms (map retrans vals) (retrans body))) - ((fix ,names ,gensyms ,vals ,body) + (('fix names gensyms vals body) (make-fix loc names gensyms (map retrans vals) (retrans body))) - ((let-values ,exp ,body) + (('let-values exp body) (make-let-values loc (retrans exp) (retrans body))) - ((dynwind ,winder ,body ,unwinder) - (make-dynwind loc (retrans winder) (retrans body) (retrans unwinder))) - - ((dynlet ,fluids ,vals ,body) - (make-dynlet loc (map retrans fluids) (map retrans vals) (retrans body))) - - ((dynref ,fluid) - (make-dynref loc (retrans fluid))) - - ((dynset ,fluid ,exp) - (make-dynset loc (retrans fluid) (retrans exp))) - - ((prompt ,tag ,body ,handler) - (make-prompt loc (retrans tag) (retrans body) (retrans handler))) - - ((abort ,tag ,args ,tail) + (('prompt escape-only? tag body handler) + (make-prompt loc escape-only? + (retrans tag) (retrans body) (retrans handler))) + + (('abort tag args tail) (make-abort loc (retrans tag) (map retrans args) (retrans tail))) (else (error "unrecognized tree-il" exp))))) (define (unparse-tree-il tree-il) - (record-case tree-il - (() + (match tree-il + (($ src) '(void)) - (( proc args) - `(apply ,(unparse-tree-il proc) ,@(map unparse-tree-il args))) + (($ src proc args) + `(call ,(unparse-tree-il proc) ,@(map unparse-tree-il args))) + + (($ src name args) + `(primcall ,name ,@(map unparse-tree-il args))) - (( test consequent alternate) - `(if ,(unparse-tree-il test) ,(unparse-tree-il consequent) ,(unparse-tree-il alternate))) + (($ src test consequent alternate) + `(if ,(unparse-tree-il test) + ,(unparse-tree-il consequent) + ,(unparse-tree-il alternate))) - (( name) + (($ src name) `(primitive ,name)) - (( name gensym) + (($ src name gensym) `(lexical ,name ,gensym)) - (( name gensym exp) + (($ src name gensym exp) `(set! (lexical ,name ,gensym) ,(unparse-tree-il exp))) - (( mod name public?) + (($ src mod name public?) `(,(if public? '@ '@@) ,mod ,name)) - (( mod name public? exp) + (($ src mod name public? exp) `(set! (,(if public? '@ '@@) ,mod ,name) ,(unparse-tree-il exp))) - (( name) + (($ src name) `(toplevel ,name)) - (( name exp) + (($ src name exp) `(set! (toplevel ,name) ,(unparse-tree-il exp))) - (( name exp) + (($ src name exp) `(define ,name ,(unparse-tree-il exp))) - (( meta body) + (($ src meta body) (if body `(lambda ,meta ,(unparse-tree-il body)) `(lambda ,meta (lambda-case)))) - (( req opt rest kw inits gensyms body alternate) + (($ src req opt rest kw inits gensyms body alternate) `(lambda-case ((,req ,opt ,rest ,kw ,(map unparse-tree-il inits) ,gensyms) ,(unparse-tree-il body)) . ,(if alternate (list (unparse-tree-il alternate)) '()))) - (( exp) + (($ src exp) `(const ,exp)) - (( exps) - `(begin ,@(map unparse-tree-il exps))) - - (( names gensyms vals body) + (($ src head tail) + `(seq ,(unparse-tree-il head) ,(unparse-tree-il tail))) + + (($ src names gensyms vals body) `(let ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body))) - (( in-order? names gensyms vals body) + (($ src in-order? names gensyms vals body) `(,(if in-order? 'letrec* 'letrec) ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body))) - (( names gensyms vals body) + (($ src names gensyms vals body) `(fix ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body))) - (( exp body) + (($ src exp body) `(let-values ,(unparse-tree-il exp) ,(unparse-tree-il body))) - (( winder body unwinder) - `(dynwind ,(unparse-tree-il winder) ,(unparse-tree-il body) - ,(unparse-tree-il unwinder))) - - (( fluids vals body) - `(dynlet ,(map unparse-tree-il fluids) ,(map unparse-tree-il vals) - ,(unparse-tree-il body))) - - (( fluid) - `(dynref ,(unparse-tree-il fluid))) + (($ src escape-only? tag body handler) + `(prompt ,escape-only? + ,(unparse-tree-il tag) + ,(unparse-tree-il body) + ,(unparse-tree-il handler))) - (( fluid exp) - `(dynset ,(unparse-tree-il fluid) ,(unparse-tree-il exp))) - - (( tag body handler) - `(prompt ,(unparse-tree-il tag) ,(unparse-tree-il body) ,(unparse-tree-il handler))) - - (( tag args tail) + (($ src tag args tail) `(abort ,(unparse-tree-il tag) ,(map unparse-tree-il args) ,(unparse-tree-il tail))))) @@ -342,82 +337,6 @@ e env opts))) -(define (tree-il-fold leaf down up seed tree) - "Traverse TREE, calling LEAF on each leaf encountered, DOWN upon descent -into a sub-tree, and UP when leaving a sub-tree. Each of these procedures is -invoked as `(PROC TREE SEED)', where TREE is the sub-tree or leaf considered -and SEED is the current result, intially seeded with SEED. - -This is an implementation of `foldts' as described by Andy Wingo in -``Applications of fold to XML transformation''." - (let loop ((tree tree) - (result seed)) - (if (or (null? tree) (pair? tree)) - (fold loop result tree) - (record-case tree - (( exp) - (up tree (loop exp (down tree result)))) - (( exp) - (up tree (loop exp (down tree result)))) - (( exp) - (up tree (loop exp (down tree result)))) - (( exp) - (up tree (loop exp (down tree result)))) - (( test consequent alternate) - (up tree (loop alternate - (loop consequent - (loop test (down tree result)))))) - (( proc args) - (up tree (loop (cons proc args) (down tree result)))) - (( exps) - (up tree (loop exps (down tree result)))) - (( body) - (let ((result (down tree result))) - (up tree - (if body - (loop body result) - result)))) - (( inits body alternate) - (up tree (if alternate - (loop alternate - (loop body (loop inits (down tree result)))) - (loop body (loop inits (down tree result)))))) - (( vals body) - (up tree (loop body - (loop vals - (down tree result))))) - (( vals body) - (up tree (loop body - (loop vals - (down tree result))))) - (( vals body) - (up tree (loop body - (loop vals - (down tree result))))) - (( exp body) - (up tree (loop body (loop exp (down tree result))))) - (( body winder unwinder) - (up tree (loop unwinder - (loop winder - (loop body (down tree result)))))) - (( fluids vals body) - (up tree (loop body - (loop vals - (loop fluids (down tree result)))))) - (( fluid) - (up tree (loop fluid (down tree result)))) - (( fluid exp) - (up tree (loop exp (loop fluid (down tree result))))) - (( tag body handler) - (up tree - (loop tag (loop body (loop handler - (down tree result)))))) - (( tag args tail) - (up tree (loop tail (loop args (loop tag (down tree result)))))) - (else - (leaf tree result)))))) - - (define-syntax-rule (make-tree-il-folder seed ...) (lambda (tree down up seed ...) (define (fold-values proc exps seed ...) @@ -429,237 +348,222 @@ This is an implementation of `foldts' as described by Andy Wingo in (let*-values (((seed ...) (down tree seed ...)) ((seed ...) - (record-case tree - (( exp) + (match tree + (($ src name gensym exp) (foldts exp seed ...)) - (( exp) + (($ src mod name public? exp) (foldts exp seed ...)) - (( exp) + (($ src name exp) (foldts exp seed ...)) - (( exp) + (($ src name exp) (foldts exp seed ...)) - (( test consequent alternate) + (($ src test consequent alternate) (let*-values (((seed ...) (foldts test seed ...)) ((seed ...) (foldts consequent seed ...))) (foldts alternate seed ...))) - (( proc args) + (($ src proc args) (let-values (((seed ...) (foldts proc seed ...))) (fold-values foldts args seed ...))) - (( exps) - (fold-values foldts exps seed ...)) - (( body) + (($ src name args) + (fold-values foldts args seed ...)) + (($ src head tail) + (let-values (((seed ...) (foldts head seed ...))) + (foldts tail seed ...))) + (($ src meta body) (if body (foldts body seed ...) (values seed ...))) - (( inits body alternate) + (($ src req opt rest kw inits gensyms body + alternate) (let-values (((seed ...) (fold-values foldts inits seed ...))) (if alternate (let-values (((seed ...) (foldts body seed ...))) (foldts alternate seed ...)) (foldts body seed ...)))) - (( vals body) + (($ src names gensyms vals body) (let*-values (((seed ...) (fold-values foldts vals seed ...))) (foldts body seed ...))) - (( vals body) + (($ src in-order? names gensyms vals body) (let*-values (((seed ...) (fold-values foldts vals seed ...))) (foldts body seed ...))) - (( vals body) + (($ src names gensyms vals body) (let*-values (((seed ...) (fold-values foldts vals seed ...))) (foldts body seed ...))) - (( exp body) + (($ src exp body) (let*-values (((seed ...) (foldts exp seed ...))) (foldts body seed ...))) - (( body winder unwinder) - (let*-values (((seed ...) (foldts body seed ...)) - ((seed ...) (foldts winder seed ...))) - (foldts unwinder seed ...))) - (( fluids vals body) - (let*-values (((seed ...) (fold-values foldts fluids seed ...)) - ((seed ...) (fold-values foldts vals seed ...))) - (foldts body seed ...))) - (( fluid) - (foldts fluid seed ...)) - (( fluid exp) - (let*-values (((seed ...) (foldts fluid seed ...))) - (foldts exp seed ...))) - (( tag body handler) + (($ src escape-only? tag body handler) (let*-values (((seed ...) (foldts tag seed ...)) ((seed ...) (foldts body seed ...))) (foldts handler seed ...))) - (( tag args tail) + (($ src tag args tail) (let*-values (((seed ...) (foldts tag seed ...)) ((seed ...) (fold-values foldts args seed ...))) (foldts tail seed ...))) - (else + (_ (values seed ...))))) (up tree seed ...))))) -(define (post-order! f x) - (let lp ((x x)) - (record-case x - (( proc args) - (set! (application-proc x) (lp proc)) - (set! (application-args x) (map lp args))) - - (( test consequent alternate) - (set! (conditional-test x) (lp test)) - (set! (conditional-consequent x) (lp consequent)) - (set! (conditional-alternate x) (lp alternate))) - - (( name gensym exp) - (set! (lexical-set-exp x) (lp exp))) - - (( mod name public? exp) - (set! (module-set-exp x) (lp exp))) - - (( name exp) - (set! (toplevel-set-exp x) (lp exp))) - - (( name exp) - (set! (toplevel-define-exp x) (lp exp))) - - (( body) - (if body - (set! (lambda-body x) (lp body)))) - - (( inits body alternate) - (set! inits (map lp inits)) - (set! (lambda-case-body x) (lp body)) - (if alternate - (set! (lambda-case-alternate x) (lp alternate)))) - - (( exps) - (set! (sequence-exps x) (map lp exps))) - - (( gensyms vals body) - (set! (let-vals x) (map lp vals)) - (set! (let-body x) (lp body))) - - (( gensyms vals body) - (set! (letrec-vals x) (map lp vals)) - (set! (letrec-body x) (lp body))) - - (( gensyms vals body) - (set! (fix-vals x) (map lp vals)) - (set! (fix-body x) (lp body))) +(define (tree-il-fold down up seed tree) + "Traverse TREE, calling DOWN before visiting a sub-tree, and UP when +after visiting it. Each of these procedures is invoked as `(PROC TREE +SEED)', where TREE is the sub-tree considered and SEED is the current +result, intially seeded with SEED. - (( exp body) - (set! (let-values-exp x) (lp exp)) - (set! (let-values-body x) (lp body))) - - (( body winder unwinder) - (set! (dynwind-body x) (lp body)) - (set! (dynwind-winder x) (lp winder)) - (set! (dynwind-unwinder x) (lp unwinder))) - - (( fluids vals body) - (set! (dynlet-fluids x) (map lp fluids)) - (set! (dynlet-vals x) (map lp vals)) - (set! (dynlet-body x) (lp body))) - - (( fluid) - (set! (dynref-fluid x) (lp fluid))) - - (( fluid exp) - (set! (dynset-fluid x) (lp fluid)) - (set! (dynset-exp x) (lp exp))) - - (( tag body handler) - (set! (prompt-tag x) (lp tag)) - (set! (prompt-body x) (lp body)) - (set! (prompt-handler x) (lp handler))) - - (( tag args tail) - (set! (abort-tag x) (lp tag)) - (set! (abort-args x) (map lp args)) - (set! (abort-tail x) (lp tail))) - - (else #f)) - - (or (f x) x))) - -(define (pre-order! f x) +This is an implementation of `foldts' as described by Andy Wingo in +``Applications of fold to XML transformation''." + ;; Multi-valued fold naturally puts the seeds at the end, whereas + ;; normal fold puts the traversable at the end. Adapt to the expected + ;; argument order. + ((make-tree-il-folder tree) tree down up seed)) + +(define (pre-post-order pre post x) + (define (elts-eq? a b) + (or (null? a) + (and (eq? (car a) (car b)) + (elts-eq? (cdr a) (cdr b))))) (let lp ((x x)) - (let ((x (or (f x) x))) - (record-case x - (( proc args) - (set! (application-proc x) (lp proc)) - (set! (application-args x) (map lp args))) - - (( test consequent alternate) - (set! (conditional-test x) (lp test)) - (set! (conditional-consequent x) (lp consequent)) - (set! (conditional-alternate x) (lp alternate))) - - (( exp) - (set! (lexical-set-exp x) (lp exp))) - - (( exp) - (set! (module-set-exp x) (lp exp))) - - (( exp) - (set! (toplevel-set-exp x) (lp exp))) - - (( exp) - (set! (toplevel-define-exp x) (lp exp))) - - (( body) - (if body - (set! (lambda-body x) (lp body)))) - - (( inits body alternate) - (set! inits (map lp inits)) - (set! (lambda-case-body x) (lp body)) - (if alternate (set! (lambda-case-alternate x) (lp alternate)))) - - (( exps) - (set! (sequence-exps x) (map lp exps))) - - (( vals body) - (set! (let-vals x) (map lp vals)) - (set! (let-body x) (lp body))) - - (( vals body) - (set! (letrec-vals x) (map lp vals)) - (set! (letrec-body x) (lp body))) - - (( vals body) - (set! (fix-vals x) (map lp vals)) - (set! (fix-body x) (lp body))) - - (( exp body) - (set! (let-values-exp x) (lp exp)) - (set! (let-values-body x) (lp body))) - - (( body winder unwinder) - (set! (dynwind-body x) (lp body)) - (set! (dynwind-winder x) (lp winder)) - (set! (dynwind-unwinder x) (lp unwinder))) - - (( fluids vals body) - (set! (dynlet-fluids x) (map lp fluids)) - (set! (dynlet-vals x) (map lp vals)) - (set! (dynlet-body x) (lp body))) - - (( fluid) - (set! (dynref-fluid x) (lp fluid))) - - (( fluid exp) - (set! (dynset-fluid x) (lp fluid)) - (set! (dynset-exp x) (lp exp))) - - (( tag body handler) - (set! (prompt-tag x) (lp tag)) - (set! (prompt-body x) (lp body)) - (set! (prompt-handler x) (lp handler))) - - (( tag args tail) - (set! (abort-tag x) (lp tag)) - (set! (abort-args x) (map lp args)) - (set! (abort-tail x) (lp tail))) - - (else #f)) - x))) + (post + (let ((x (pre x))) + (match x + ((or ($ ) + ($ ) + ($ ) + ($ ) + ($ ) + ($ )) + x) + + (($ src name gensym exp) + (let ((exp* (lp exp))) + (if (eq? exp exp*) + x + (make-lexical-set src name gensym exp*)))) + + (($ src mod name public? exp) + (let ((exp* (lp exp))) + (if (eq? exp exp*) + x + (make-module-set src mod name public? exp*)))) + + (($ src name exp) + (let ((exp* (lp exp))) + (if (eq? exp exp*) + x + (make-toplevel-set src name exp*)))) + + (($ src name exp) + (let ((exp* (lp exp))) + (if (eq? exp exp*) + x + (make-toplevel-define src name exp*)))) + + (($ src test consequent alternate) + (let ((test* (lp test)) + (consequent* (lp consequent)) + (alternate* (lp alternate))) + (if (and (eq? test test*) + (eq? consequent consequent*) + (eq? alternate alternate*)) + x + (make-conditional src test* consequent* alternate*)))) + + (($ src proc args) + (let ((proc* (lp proc)) + (args* (map lp args))) + (if (and (eq? proc proc*) + (elts-eq? args args*)) + x + (make-call src proc* args*)))) + + (($ src name args) + (let ((args* (map lp args))) + (if (elts-eq? args args*) + x + (make-primcall src name args*)))) + + (($ src head tail) + (let ((head* (lp head)) + (tail* (lp tail))) + (if (and (eq? head head*) + (eq? tail tail*)) + x + (make-seq src head* tail*)))) + + (($ src meta body) + (let ((body* (and body (lp body)))) + (if (eq? body body*) + x + (make-lambda src meta body*)))) + + (($ src req opt rest kw inits gensyms body alternate) + (let ((inits* (map lp inits)) + (body* (lp body)) + (alternate* (and alternate (lp alternate)))) + (if (and (elts-eq? inits inits*) + (eq? body body*) + (eq? alternate alternate*)) + x + (make-lambda-case src req opt rest kw inits* gensyms body* + alternate*)))) + + (($ src names gensyms vals body) + (let ((vals* (map lp vals)) + (body* (lp body))) + (if (and (elts-eq? vals vals*) + (eq? body body*)) + x + (make-let src names gensyms vals* body*)))) + + (($ src in-order? names gensyms vals body) + (let ((vals* (map lp vals)) + (body* (lp body))) + (if (and (elts-eq? vals vals*) + (eq? body body*)) + x + (make-letrec src in-order? names gensyms vals* body*)))) + + (($ src names gensyms vals body) + (let ((vals* (map lp vals)) + (body* (lp body))) + (if (and (elts-eq? vals vals*) + (eq? body body*)) + x + (make-fix src names gensyms vals* body*)))) + + (($ src exp body) + (let ((exp* (lp exp)) + (body* (lp body))) + (if (and (eq? exp exp*) + (eq? body body*)) + x + (make-let-values src exp* body*)))) + + (($ src escape-only? tag body handler) + (let ((tag* (lp tag)) + (body* (lp body)) + (handler* (lp handler))) + (if (and (eq? tag tag*) + (eq? body body*) + (eq? handler handler*)) + x + (make-prompt src escape-only? tag* body* handler*)))) + + (($ src tag args tail) + (let ((tag* (lp tag)) + (args* (map lp args)) + (tail* (lp tail))) + (if (and (eq? tag tag*) + (elts-eq? args args*) + (eq? tail tail*)) + x + (make-abort src tag* args* tail*))))))))) + +(define (post-order f x) + (pre-post-order (lambda (x) x) f x)) + +(define (pre-order f x) + (pre-post-order f (lambda (x) x) x)) ;; FIXME: We should have a better primitive than this. (define (struct-nfields x)