#! /usr/bin/mzscheme #lang scheme (define (trace fn . args) (let ([x (apply fn args)]) (pretty-print x) x)) (define (simplify-form form) (if (pair? form) (case (car form) [(let) (simplify-let form)] [(let*) (simplify-let* form)] [(letrec) (simplify-letrec form)] [(if) (simplify-if form)] [(lambda) (simplify-lambda form)] [(begin) `(%bind () ,@(map simplify-form (cdr form)))] [(set!) (simplify-set! form)] [(car cdr cons) (simplify-primitive (case (first form) [(car) '%car] [(cdr) '%cdr] [(cons) '%cons]) (cdr form))] [(%bind %if %tail-call %apply %lambda %set! %cons %car %cdr) form] [else (simplify-funcall form)]) (if (eq? form '()) '%nil form))) (define (simplify-set! form) (let ([value-form (simplify-form (third form))]) (if (and (pair? value-form) (eq? (first value-form) '%bind)) `(%bind ,(second value-form) ,@(foldr (lambda (subform after) (if (pair? after) (cons subform after) (if (or (not (pair? subform)) (memq (first subform) '(%apply %car %cdr %cons %bind %if))) (list (simplify-set! `(set! ,(second form) ,subform))) (list subform)))) '() (cddr value-form))) `(%set! ,(second form) ,value-form)))) (define (simplify-primitive new-id value-forms) (define bindings (map (lambda (vf) (if (pair? vf) (list (gensym) vf) (list vf vf))) value-forms)) (define temp-bindings (filter (lambda (x) (not (eq? (first x) (second x)))) bindings)) `(%bind ,(map first temp-bindings) ,@(map (lambda (x) (simplify-set! `(set! ,(first x) ,(second x)))) temp-bindings) (,new-id ,@(map first bindings)))) ; (let ([var expr]...) bodyexpr...) ; first eval exprs, then assign bindings in parallel ; => (%bind (tmp...) ; (%set! tmp ,(simplify-form expr))... ; (%bind (var...) ; (%set! var tmp)... ; bodyexpr...)) (define (simplify-let form) (define bindings (second form)) (define bodyexprs (cdr (cdr form))) (define vars (map (lambda (x) (if (pair? x) (first x) x)) bindings)) (define temp-bindings (append-map (lambda (x) (if (pair? x) (let ([tmp (gensym)]) `((,tmp ,(simplify-form `(set! ,tmp ,(second x))) (%set! ,(first x) ,tmp)))) '())) bindings)) (if (pair? bindings) (if (pair? (cdr bindings)) `(%bind ,(map first temp-bindings) ,@(map second temp-bindings) (%bind ,vars ,@(map third temp-bindings) ,@(map simplify-form bodyexprs))) `(%bind (,(first vars)) ,@(if (pair? (first bindings)) `(,(simplify-form `(set! ,(first vars) ,(second (first bindings))))) '()) ,@(map simplify-form bodyexprs))) `(%bind () ,@(map simplify-form bodyexprs)))) ; (let* ...) ; eval exprs & bind variables serially ; => (let ([var-0 expr-0]) ; (let ([var-1 expr-1]) ; (... ; bodyexprs...))) (define (simplify-let* form) (define bindings (second form)) (define bodyexprs (cdr (cdr form))) (define (add-binding bind bodyexpr) `(let (,bind) ,bodyexpr)) (simplify-form (foldr add-binding `(begin ,@bodyexprs) bindings))) ; (letrec ...) ; init bindings to undefined, then assign values in series ; => (let (var...) ; (set! var expr)... ; bodyexprs) (define (simplify-letrec form) (define bindings (second form)) (define bodyexprs (cdr (cdr form))) `(%bind (,@(map (lambda (x) (if (pair? x) (first x) x)) bindings)) ,@(append-map (lambda (x) (if (pair? x) `(,(simplify-form `(set! ,(first x) ,(simplify-form (second x))))) '())) bindings) ,@(map simplify-form bodyexprs))) (define (simplify-if form) (define cond-val (gensym)) (define next-fn (gensym)) (define true-fn (gensym)) (define false-fn (gensym)) (define-values (cond-expr true-expr false-expr) (apply values (cdr form))) (simplify-form (if (or (pair? true-expr) (pair? false-expr)) `(let ([,cond-val ,cond-expr] [,true-fn (lambda () ,true-expr)] [,false-fn (lambda () ,false-expr)]) (let ([,next-fn (%if ,cond-val ,true-fn ,false-fn)]) (%apply ,next-fn %nil))) `(let ([,cond-val ,cond-expr]) (%if ,cond-val ,(simplify-form true-expr) ,(simplify-form false-expr)))))) ; (lambda (required... [optional default-expr]... . rest) bodyexpr...) ; => (lambda argv ; (let ([argv-temp argv]) ; (let ([required-0 (car argv-temp)]) ; (set! argv-temp (cdr argv-temp))) ; (let ([required-1 (car argv-temp)]) ; (set! argv-temp (cdr argv-temp))) ; (... ; (let (optional-0) ; (if (eq? argv-temp %nil) ; (set! optional-0 default-expr-0) ; (set! optional-0 (car argv-temp))) ; (set! argv-temp (cdr argv-temp)) ; (let (optional-1) ; (if (eq? argv-temp %nil) ; (set! optional-1 default-expr-1) ; (set! optional-1 (car argv-temp))) ; (set! argv-temp (cdr argv-temp)) ; (... ; (let ([rest argv-temp]) ; bodyexpr...)...)))...))) (define (split-arglist arglist) (define (split-optional arglist) (if (pair? arglist) (let-values ([(opt rst) (split-optional (cdr arglist))]) (values (cons (car arglist) opt) rst)) (values '() arglist))) (if (pair? arglist) (if (pair? (car arglist)) (let-values ([(opt rst) (split-optional arglist)]) (values '() opt rst)) (let-values ([(req opt rst) (split-arglist (cdr arglist))]) (values (cons (car arglist) req) opt rst))) (values '() '() #f))) (define (add-tail-call k rval form) `(%bind ,(second form) ,@(foldr (lambda (subform after) (if (pair? after) (cons subform after) (if (and (pair? subform) (eq? (first subform) '%set!) (eq? (second subform) rval) (pair? (third subform)) (eq? (first (third subform)) '%apply)) (let ([fn (second (third subform))] [argv (third (third subform))]) `((%tail-call ,fn ,argv ,k))) (if (and (pair? subform) (eq? (first subform) '%tail-call)) (list subform) (if (and (pair? subform) (eq? (first subform) '%apply)) `((%tail-call ,(second subform) ,(third subform) ,k)) (if (and (pair? subform) (eq? (first subform) '%set!) (eq? (second subform) rval)) `(,subform (%set! ,rval (%cons ,rval %nil)) (%tail-call ,k ,rval #f)) `(,subform (%tail-call ,k %nil #f)))))))) '() (cddr form)))) (define (simplify-lambda form) (define arglist (car (cdr form))) (define bodyexprs (cdr (cdr form))) (define-values (requireds optionals rest) (split-arglist arglist)) (define argv-temp (gensym)) (define k (gensym)) (define rval (gensym)) (define (add-req req inner) `(let ([,req (car ,argv-temp)]) (set! ,argv-temp (cdr ,argv-temp)) ,inner)) (define (add-opt opt-list inner) `(let (,(car opt-list)) (if (pair? ,argv-temp) (begin (set! ,(first opt-list) (car ,argv-temp)) (set! ,argv-temp (cdr ,argv-temp))) (set! ,(first opt-list) ,(second opt-list))) ,inner)) (define rest+bodyexprs (if rest `(let ([,rest ,argv-temp]) ,@bodyexprs) `(begin ,@bodyexprs))) `(%lambda ,(transform-to-cps (add-tail-call k rval (flatten-binds `(%bind (,rval ,k) (%set! ,k %k) ,(make-bindings-unique (simplify-form `(set! ,rval (let ([,argv-temp %argv]) ,(foldr add-req (foldr add-opt rest+bodyexprs optionals) requireds))))))))))) ; <= (%bind (var...) ; @before ; (%apply x y) ; @after)) ; => (%bind (var... k) ; @before ; (%set k (lambda _ @after)) ; (%tail-call x y k))) ; <= (%bind (var...) ; @before ; (%set v (%apply x y)) ; @after)) ; => (%bind (var... k) ; @before ; (%set k (lambda (x) ; (%set! v x) ; @after)) ; (%tail-call x y k))) (define (transform-to-cps form) (flatten-binds `(%bind ,(second form) ,@(foldr (lambda (subform after) (cond [(and (pair? subform) (eq? (first subform) '%set!) (pair? (third subform)) (eq? (first (third subform)) '%apply)) (let ([k (gensym)] [x (gensym)]) `((%bind (,k ,x) (%set! ,k ,(simplify-form `(lambda (,x) (%set! ,(second subform) ,x) ,@after))) (%tail-call ,(second (third subform)) ,(third (third subform)) ,k))))] [(and (pair? subform) (eq? (first subform) '%apply)) (let ([k (gensym)]) `((%bind (,k) (%set! ,k ,(simplify-form `(lambda ,(gensym) ,@after))) (%tail-call ,(second subform) ,(third subform) ,k))))] [else (cons subform after)])) '() (cddr form))))) ; (fn-expr arg-expr...) ; => (let ([fn-var fn-expr] arg-var... argv) ; (set! fn-var fn-expr) ; (set! arg-var arg-expr)... ; (set! argv %nil) ; (set! argv (cons arg-var argv))... [reversed] ; (%apply fn-var argv)) (define (simplify-funcall form) (define fn-expr (car form)) (define arg-exprs (cdr form)) (define fn-var (gensym)) (define arg-vars (map (lambda (x) (gensym)) arg-exprs)) (define argv (gensym)) `(%bind (,fn-var ,@arg-vars ,argv) ,(simplify-form `(set! ,fn-var ,fn-expr)) ,@(map (lambda (x y) (simplify-form `(set! ,x ,y))) arg-vars arg-exprs) (%set! ,argv %nil) ,@(reverse (map (lambda (x) `(%set! ,argv (%cons ,x ,argv))) arg-vars)) (%apply ,fn-var ,argv))) (define (subst-var old-var new-var form) (define (recurse form) (subst-var old-var new-var form)) (if (pair? form) (case (car form) [(%bind) (if (memq old-var (second form)) form `(%bind ,(second form) ,@(map recurse (cddr form))))] [(%if %tail-call %apply %lambda %set! %cons %car %cdr) `(,(first form) ,@(map recurse (cdr form)))] [else (error "Unsimplified form:" form)]) (if (eq? form old-var) new-var form))) (define (make-bindings-unique form) (if (pair? form) (case (car form) [(%bind) (let ([new-vars (map (lambda _ (gensym)) (second form))]) `(%bind ,new-vars ,@(map (lambda (frm) (foldl (lambda (pair s) (subst-var (car pair) (cdr pair) s)) (make-bindings-unique frm) (map cons (second form) new-vars))) (cddr form))))] [(%if %tail-call %apply %lambda %set! %cons %car %cdr) form] [else (error "Unsimplified form:" form)]) form)) (define (flatten-binds form) ;(pretty-print form) (write-char #\Newline) (if (pair? form) (case (car form) [(%bind) (let* ([bound-vars (second form)] [subforms (append-map (lambda (new-form) (if (and (pair? new-form) (eq? (car new-form) '%bind)) (begin (set! bound-vars (append bound-vars (second new-form))) (cddr new-form)) (list new-form))) (map flatten-binds (cddr form)))]) `(%bind ,bound-vars ,@subforms))] [(%if %tail-call %apply %set! %lambda %cons %car %cdr) form] [else (error "Unsimplified form:" form)]) form)) (define (compile-lambda lambda-form) (flatten-binds (make-bindings-unique (simplify-form lambda-form)))) (define (compile form) (compile-lambda `(lambda () ,form))) (define (free-variables form [input? #t] [output? #t]) (define (recurse form) (free-variables form input? output?)) (if (pair? form) (case (car form) [(%bind) (remove* (second form) (remove-duplicates (append-map recurse (cddr form))))] [(%set!) (if output? (cons (second form) (recurse (third form))) (recurse (third form)))] [(%if %tail-call %apply %lambda %cons %car %cdr) (remove-duplicates (append-map recurse (cdr form)))] [else (error "Unsimplified form:" form)]) (if (and input? (symbol? form) (not (memq form '(%nil %self %argv %ctx %k)))) (list form) '()))) (define (free-input-variables form) (free-variables form #t #f)) (define (free-output-variables form) (free-variables form #f #t)) ; Don't bind variables which aren't referenced. (define (reduce-variables form) (if (pair? form) (case (car form) [(%bind) (let ([ref-vars (remove-duplicates (append-map free-variables (cddr form)))]) `(%bind ,(filter (lambda (x) (memq x ref-vars)) (second form)) ,@(map reduce-variables (cddr form))))] [(%if %tail-call %apply %set! %lambda %cons %car %cdr) `(,(first form) ,@(map reduce-variables (cdr form)))] [else (error "Unsimplified form:" form)]) form)) ; Don't set variables which won't be accessed later. (define (reduce-set! form) (if (pair? form) (case (car form) [(%bind) (let ([free-vars (free-variables form)]) `(%bind ,(second form) ,@(foldr (lambda (subform after) (if (and (pair? subform) (eq? (first subform) '%set!) (not (memq (second subform) free-vars)) (not (memq (second subform) (append-map free-input-variables after)))) after (cons subform after))) '() (map reduce-set! (cddr form)))))] [(%if %tail-call %apply %set! %lambda %cons %car %cdr) `(,(first form) ,@(map reduce-set! (cdr form)))] [else (error "Unsimplified form:" form)]) form)) (define (optimize form) (reduce-variables (reduce-set! form))) ;(void (trace optimize (trace compile-lambda (trace simplify-form `(lambda () ,(read)))))) ;(pretty-print (compile (read))) (pretty-print (optimize (compile (read)))) ; vim:set sw=2 expandtab: