#lang s-exp "../lang.ss"
(require "anormal-frag-helpers.ss")
(require "munge-ids.ss")
(require "../../collects/moby/runtime/stx.ss")
(define anon-prepend "anon~a")
(define (fold-elim-anon-help expr)
(local [(define reversed-info
(foldl (lambda (an-expr new-info)
(let ([rec-info (elim-anon-help an-expr)])
(make-linfo (cons (linfo-return rec-info)
(linfo-return new-info))
(append (linfo-raise new-info)
(linfo-raise rec-info)))))
(make-linfo empty empty)
(stx-e expr)))]
(make-linfo (datum->stx false
(reverse (linfo-return reversed-info))
(stx-loc expr))
(linfo-raise reversed-info))))
(define (elim-anon-help expr)
(if (stx:atom? expr)
(make-linfo expr empty)
(let* ([expr-list (stx-e expr)]
[first-elt (stx-e (first expr-list))])
(cond
[(equal? first-elt 'lambda)
(let ([new-proc-name (string->symbol (format anon-prepend (gensym)))]
[rec-info (elim-anon-help (third expr-list))])
(make-linfo (datum->stx false new-proc-name (stx-loc expr))
(list
(datum->stx false
(list 'define
(cons new-proc-name
(stx-e (second expr-list)))
(if (empty? (linfo-raise rec-info))
(linfo-return rec-info)
(list 'local
(linfo-raise rec-info)
(linfo-return rec-info))))
(stx-loc expr)))))]
[(equal? first-elt 'define)
(let* ([sugared-def (ensugar expr)]
[rec-info (elim-anon-help (third (stx-e sugared-def)))])
(make-linfo (datum->stx false
(list 'define
(second (stx-e sugared-def))
(if (empty? (linfo-raise rec-info))
(linfo-return rec-info)
(list 'local
(linfo-raise rec-info)
(linfo-return rec-info))))
(stx-loc expr))
empty))]
[(equal? first-elt 'local)
(let ([new-defs (map elim-anon (stx-e (second expr-list)))]
[rec-info (elim-anon-help (third expr-list))])
(make-linfo (datum->stx false
(list 'local
(append new-defs
(linfo-raise rec-info))
(linfo-return rec-info))
(stx-loc expr))
empty))]
[(or (equal? first-elt 'quote)
(equal? first-elt 'define-struct)
(equal? first-elt 'require))
(make-linfo expr empty)]
[(equal? first-elt 'begin)
(make-linfo (datum->stx false
(map elim-anon expr-list)
(stx-loc expr))
empty)]
[else (fold-elim-anon-help expr)]))))
(define (elim-anon expr)
(let ([lifted (elim-anon-help expr)])
(if (empty? (linfo-raise lifted))
(linfo-return lifted)
(datum->stx false
(list 'local
(linfo-raise lifted)
(linfo-return lifted))
(stx-loc expr)))))
(define (name-anon-procs expr)
(begin
(reset-gensym)
(elim-anon expr)))
(define (lift-struct-defs expr)
(let ([lifted (lift-struct-defs-help (munge-identifiers expr))])
(datum->stx false
(append (linfo-raise lifted)
(stx-e (linfo-return lifted)))
(stx-loc expr))))
(define (fold-lift-struct-defs-help expr-list)
(foldr (lambda (expr info)
(let ([output (lift-struct-defs-help expr)])
(make-linfo (cons (linfo-return output)
(linfo-return info))
(append (linfo-raise output)
(linfo-raise info)))))
(make-linfo empty empty)
expr-list))
(define (lift-struct-defs-help expr)
(if (stx:atom? expr)
(make-linfo expr empty)
(let* ([expr-list (stx-e expr)]
[first-elt (stx-e (first expr-list))])
(cond
[(equal? first-elt 'local)
(let ([struct-defs
(filter (lambda (a-def) (equal? (stx-e (first (stx-e a-def)))
'define-struct))
(stx-e (second expr-list)))]
[other-defs
(fold-lift-struct-defs-help
(filter (lambda (a-def) (equal? (stx-e (first (stx-e a-def)))
'define))
(stx-e (second expr-list))))])
(make-linfo (datum->stx false
(if (empty? (linfo-return other-defs))
(third expr-list)
(list 'local
(linfo-return other-defs)
(third expr-list)))
(stx-loc expr))
(append struct-defs
(linfo-raise other-defs))))]
[(or (equal? first-elt 'quote)
(equal? first-elt 'define-struct)
(equal? first-elt 'require))
(make-linfo expr empty)]
[else (let ([folded-list (fold-lift-struct-defs-help expr-list)])
(make-linfo (datum->stx false
(linfo-return folded-list)
(stx-loc expr))
(linfo-raise folded-list)))]))))
(provide/contract
[name-anon-procs (stx? . -> . stx?)]
[lift-struct-defs (stx? . -> . stx?)])