racket/collects/syntax/modcollapse.ss
2007-04-17 13:52:13 +00:00

145 lines
5.9 KiB
Scheme

(module modcollapse mzscheme
(require (lib "list.ss")
(lib "contract.ss")
"private/modhelp.ss")
(define (collapse-module-path s relto-mp)
;; relto-mp should be a relative path, '(lib relative-path collection),
;; or '(file path) or a thunk that produces one of those
;; Used for 'lib paths, so it's always Unix-style
(define (attach-to-relative-path-string elements relto)
(let ([elem-str
(substring
(apply string-append
(map (lambda (i)
(string-append
"/"
(cond [(bytes? i) (bytes->string/locale i)]
[(path? i) (path->string i)]
[(eq? i 'up) ".."]
[else i])))
(filter (lambda (x) (not (eq? x 'same)))
elements)))
1)])
(if (or (regexp-match #rx"^[.]/+[^/]*" relto)
(not (regexp-match #rx"/" relto)))
elem-str
(let ([m (regexp-match #rx"^(.*/)/*[^/]*$" relto)])
(string-append (cadr m) elem-str)))))
(define (combine-relative-elements elements)
;; Used for 'file paths, so it's platform specific:
(define (attach-to-relative-path relto)
(apply build-path
(let-values ([(base n d?) (split-path relto)])
(if (eq? base 'relative) 'same base))
(map (lambda (i) (if (bytes? i) (bytes->path i) i))
elements)))
(when (procedure? relto-mp) (set! relto-mp (relto-mp)))
(cond
[(or (path? relto-mp) (and (string? relto-mp) (ormap path? elements)))
(apply build-path
(let-values ([(base name dir?) (split-path relto-mp)])
(if (eq? base 'relative) 'same base))
(map (lambda (x) (if (bytes? x) (bytes->path x) x))
elements))]
[(string? relto-mp)
(bytes->string/locale
(apply
bytes-append
(cond [(regexp-match #rx#"^(.*)/[^/]*$"
(string->bytes/locale relto-mp))
=> cadr]
[else #"."])
(map (lambda (e)
(cond [(eq? e 'same) #"/."]
[(eq? e 'up) #"/.."]
[else (bytes-append
#"/" (if (path? e) (path->bytes e) e))]))
elements)))]
[(eq? (car relto-mp) 'file)
(let ([path ((if (ormap path? elements) values path->string)
(attach-to-relative-path (cadr relto-mp)))])
(if (path? path) path `(file ,path)))]
[(eq? (car relto-mp) 'lib)
(let ([path (attach-to-relative-path-string
elements (cadr relto-mp))])
`(lib ,path ,(caddr relto-mp)))]
[(eq? (car relto-mp) 'planet)
(let ([pathstr (attach-to-relative-path-string
elements (cadr relto-mp))])
`(planet ,pathstr ,(caddr relto-mp)))]
[else (error 'combine-relative-elements
"don't know how to deal with: ~s" relto-mp)]))
(cond [(string? s)
;; Parse Unix-style relative path string
(combine-relative-elements (explode-relpath-string s))]
[(and (or (not (pair? s)) (not (list? s))) (not (path? s)))
#f]
[(or (path? s) (eq? (car s) 'file))
(let ([p (if (path? s) s (cadr s))])
(if (absolute-path? p)
s
(let loop ([p p] [elements null])
(let-values ([(base name dir?) (split-path p)])
(cond [(eq? base 'relative)
(combine-relative-elements (cons name elements))]
[else (loop base (cons name elements))])))))]
[(eq? (car s) 'lib)
(let ([cols (let ([len (length s)])
(if (= len 2) (list "mzlib") (cddr s)))])
`(lib ,(attach-to-relative-path-string
(append (cdr cols) (list (cadr s)))
".")
,(car cols)))]
[(eq? (car s) 'planet)
(let ([cols (cdddr s)])
`(planet
,(attach-to-relative-path-string
(append cols (list (cadr s)))
".")
,(caddr s)))]
[else #f]))
(define (collapse-module-path-index mpi relto-mp)
(let-values ([(path base) (module-path-index-split mpi)])
(if path
(collapse-module-path
path
(cond
[(symbol? base)
(let ([s (symbol->string base)])
(if (and ((string-length s) . > . 0)
(char=? #\, (string-ref s 0)))
`(file ,(substring s 1))
relto-mp))]
[(module-path-index? base)
(collapse-module-path-index base relto-mp)]
[else relto-mp]))
relto-mp)))
(define simple-rel-to-module-path-v/c
(or/c
(list/c (symbols 'lib) module-path-v-string? module-path-v-string?)
(list/c (symbols 'file) (and/c string? path-string?))
;; not quite specific enough of a contract -- it should also spell out
;; what's allowed in the package spec
(cons/c (symbols 'planet)
(cons/c string? (cons/c (listof any/c) (listof string?))))
path-string?))
(define rel-to-module-path-v/c
(or/c simple-rel-to-module-path-v/c (-> simple-rel-to-module-path-v/c)))
(provide/contract
[collapse-module-path (module-path-v? rel-to-module-path-v/c
. -> . simple-rel-to-module-path-v/c)]
[collapse-module-path-index ((or/c symbol? module-path-index?)
rel-to-module-path-v/c
. -> . simple-rel-to-module-path-v/c)]))