racket/collects/r6rs/private/helpers.ss
Matthew Flatt b97ed46ad1 revised export syntax
svn: r470
2005-07-27 21:47:11 +00:00

329 lines
9.0 KiB
Scheme

(module helpers mzscheme
(require (lib "list.ss")
"uri.ss")
(require-for-template mzscheme)
(provide translate-import
translate-export
uri?)
(define (uri? s)
;; Need a proper test here!
#t)
(define ((check-identifier stx) id)
(unless (identifier? id)
(raise-syntax-error
#f
"expected an identifier"
stx
id)))
(define (check-present orig-i what nested !not exceptions names)
(for-each (lambda (en)
(unless (!not (ormap (lambda (i) (bound-identifier=? (car en) i))
names))
(raise-syntax-error
#f
(format "~a in nested ~a" what nested)
orig-i
(car en))))
exceptions))
(define (add-prefix prefix id)
(if prefix
(datum->syntax-object id
(string->symbol
(format "~a~a" (syntax-e prefix) (syntax-e id)))
id)
id))
(define (locate-rename id renames)
(cond
[(null? renames) #f]
[(bound-identifier=? id (caar renames)) (cdar renames)]
[else (locate-rename id (cdr renames))]))
(define (apply-rename new-names old-names name-pairs rcons)
(map (lambda (i)
(or (ormap (lambda (new old)
(and (bound-identifier=? (car i) new)
(rcons old (cdr i))))
new-names old-names)
i))
name-pairs))
(define (remove-all-prefixes orig-i name-pairs form prefix)
(let ([s (symbol->string (syntax-e prefix))])
(map (lambda (i)
(let ([old (symbol->string (syntax-e (car i)))])
(unless (and ((string-length old) . >= . (string-length s))
(string=? s (substring old 0 (string-length s))))
(raise-syntax-error
#f
(format "~a does not have prefix ~s added by nested `prefix' form"
form
s)
orig-i
(car i)))
(cons (datum->syntax-object (car i)
(string->symbol (substring old (string-length s)))
(car i))
(cdr i))))
name-pairs)))
(define (check-unique-names orig-i what names)
(let ([dup (check-duplicate-identifier names)])
(when dup
(raise-syntax-error
#f
(format "duplicate ~a identifier" what)
orig-i
dup))))
(define (localize i stx)
(datum->syntax-object i (syntax-e stx)))
(define (translate-import i)
(define orig-i #`(import #,i))
(syntax-case* i (for run expand) (lambda (a b) (eq? (syntax-e a) (syntax-e b)))
[(for sub run expand)
(finish-translate-import orig-i #'sub #t #t)]
[(for sub expand run)
(finish-translate-import orig-i #'sub #t #t)]
[(for sub run)
(finish-translate-import orig-i #'sub #t #f)]
[(for sub expand)
(finish-translate-import orig-i #'sub #f #t)]
[(for . _)
(raise-syntax-error
#f
"bad `for' form"
orig-i
i)]
[_else
(finish-translate-import orig-i i #t #f)]))
(define (finish-translate-import orig-i i run? expand?)
(define (mk-require l)
(cond
[(and run? expand?)
#`(begin (require #,@l) (require-for-syntax #,@l))]
[run?
#`(require #,@l)]
[expand?
#`(require-for-syntax #,@l)]))
(translate-impexp
i orig-i
(lambda (i exceptions onlys renames extra-prefix)
;; Found a base URI?
(unless (and (string? (syntax-e i))
(uri? (syntax-e i)))
(raise-syntax-error
#f
"expected a URI string or an `only', `except', `add-prefix', or `rename' form"
orig-i
i))
(let ([name (datum->syntax-object i (uri->module-path (syntax-e i)) i)])
(cond
[onlys
;; Onlys are implemented with `rename':
(mk-require (map (lambda (name-pair)
#`(rename #,name #,(cdr name-pair) #,(car name-pair)))
onlys))]
[(or exceptions (pair? renames))
;; First import non-renamed, then renamed:
(mk-require (cons
(localize i #`(#,(if extra-prefix #'prefix-all-except #'all-except)
#,@(if extra-prefix (list extra-prefix) null)
#,name
#,@(append (map car (or exceptions null))
(map car renames))))
(map (lambda (i)
#`(rename #,name #,(cdr i) #,(car i)))
renames)))]
[extra-prefix
(mk-require (list (localize i #`(prefix #,extra-prefix #,name))))]
[else
(mk-require (list name))])))))
(define (translate-export i)
(define orig-i #`(export #,i))
#`(provide
#,@(syntax-case* i (rename) (lambda (a b) (eq? (syntax-e a) (syntax-e b)))
[(rename ie ...)
(begin
(for-each (lambda (ie)
(syntax-case ie ()
[(int ext)
(for-each (lambda (i)
(unless (identifier? i)
(raise-syntax-error
#f
"expected an identifier for rename"
orig-i
i)))
(list #'int #'ext))]))
(syntax->list #'(ie ...)))
#`((rename . ie) ...))]
[(rename . x)
(raise-syntax-error
#f
"bad rename clause"
i
orig-i)]
[_
(identifier? i)
(list i)]
[_else
(raise-syntax-error
#f
"expected an identifier or `rename' form"
orig-i
i)])))
(define (translate-impexp i orig-i k)
(let loop ([i i]
[exceptions #f] ; #f if onlys
[onlys #f] ; #f if exceptions
[renames null] ; null if onlys
[extra-prefix #f]) ; #f if onlys, already folded into exceptions & renames
(syntax-case* i (only except rename add-prefix) (lambda (a b) (eq? (syntax-e a) (syntax-e b)))
[(only sub name ...)
(let ([names (syntax->list #'(name ...))])
(for-each (check-identifier i) names)
(check-unique-names orig-i "`only'" names)
(check-present orig-i "rename not" "`only' list" values renames names)
(cond
[exceptions
(check-present orig-i "except not" "`only' list" values exceptions names)
(loop #'sub
#f
(remove* exceptions (map (lambda (i)
(cons i (or (locate-rename i renames)
(add-prefix extra-prefix i))))
names)
(lambda (a b) (bound-identifier=? (car a) (car b))))
null
#f)]
[onlys
(check-present orig-i "only not" "`only' list" values onlys names)
(loop #'sub #f onlys null #f)]
[else
(loop #'sub
#f
(map (lambda (i)
(cons i (or (locate-rename i renames)
(add-prefix extra-prefix i))))
names)
null
#f)]))]
[(only . _)
(raise-syntax-error
#f
"bad syntax"
i)]
[(except sub name ...)
(let ([names (syntax->list #'(name ...))])
(for-each (check-identifier i) names)
(check-unique-names orig-i "`except'" names)
(check-present orig-i "rename" "`except' list" not renames names)
(let ([remove-exceptions
(lambda ()
(remove* exceptions renames (lambda (a b) (bound-identifier=? (car a) (car b)))))])
(cond
[(pair? exceptions)
(check-present orig-i "except" "`except' list" not exceptions names)
;; union the exceptions
(loop #'sub
(append
(remove* exceptions (map (lambda (i)
(cons i (or (locate-rename i renames)
(add-prefix extra-prefix i))))
names)
(lambda (a b) (bound-identifier=? (car a) (car b))))
exceptions)
#f
(remove-exceptions)
extra-prefix)]
[(pair? onlys)
(check-present orig-i "only" "`except' list" not onlys names)
(loop #'sub #f onlys null #f)]
[else
(loop #'sub
(map (lambda (i)
(cons i (add-prefix extra-prefix i)))
names)
#f
(remove-exceptions)
extra-prefix)])))]
[(except . _)
(raise-syntax-error
#f
"bad syntax"
i)]
[(rename sub (new old) ...)
(let* ([new-names (syntax->list #'(new ...))]
[old-names (syntax->list #'(old ...))]
[name-pairs (map (lambda (old new)
(cons old (add-prefix extra-prefix new)))
old-names new-names)])
(for-each (check-identifier i) (apply append (map list new-names old-names)))
(check-unique-names orig-i "`rename' target" new-names)
(check-unique-names orig-i "`rename' source" old-names)
(let ([combine-renames
(lambda ()
(let ([renames (apply-rename new-names old-names renames cons)])
(append
renames
(remove* renames name-pairs
(lambda (a b)
(bound-identifier=? (car a) (car b)))))))])
(cond
[exceptions
(loop #'sub
(apply-rename new-names old-names exceptions cons)
#f
(combine-renames)
extra-prefix)]
[onlys
(loop #'sub
#f
(apply-rename new-names old-names onlys cons)
null
#f)]
[else
(loop #'sub
#f
#f
(combine-renames)
extra-prefix)])))]
[(rename . _)
(raise-syntax-error
#f
"bad syntax"
i)]
[(add-prefix sub prefix)
(cond
[onlys
(loop #'sub
#f
(remove-all-prefixes orig-i onlys "only" #'prefix)
null
#f)]
[else
(loop #'sub
(and exceptions
(remove-all-prefixes orig-i exceptions "except" #'prefix))
#f
(remove-all-prefixes orig-i renames "rename" #'prefix)
(add-prefix extra-prefix #'prefix))])]
[(add-prefix . _)
(raise-syntax-error
#f
"bad syntax"
i)]
[_else
(k i exceptions onlys renames extra-prefix)]))))