racket/collects/syntax/modresolve.rkt
Matthew Flatt 9ba663aa77 preserve submoduleness in module path index for expanded submodules
The preserved path is exposed by a new `module-path-index-submodule'
function, and `module-path-index-join' now accepts an optional
submodule path.

Also, fixed a problem with `collapse-module-path-index' when
a module path indx is built on a resolved module path that
is a submodule path.

In addition to the main repair, `collapse-module-path[-index]' is
correctly documented to allow '(quote <sym>) rel-to paths.

Finally, `collapse-module-path-index' changed to use a symbolic
resolved module path that appears as the base of a module path
index, rather than falling back to the given rel-to path. It's
possble that the old beavior was intentional, but it wasn't tested,
and it seems more likely to have been a bug.

Closes PR 12724
2012-04-24 21:10:28 -06:00

154 lines
6.1 KiB
Racket

#lang racket/base
(require racket/contract/base
"private/modhelp.rkt")
(define (force-relto relto dir? #:path? [path? #t])
(let ([relto (if (and (pair? relto)
(eq? (car relto) 'submod))
(cadr relto)
relto)]
[submod (if (and (pair? relto)
(eq? (car relto) 'submod))
(cddr relto)
null)])
(cond [(path-string? relto)
(values (and path?
(if dir?
(let-values ([(base n d?) (split-path relto)])
(when d?
(error 'resolve-module-path-index
"given a directory path instead of a file path: ~e" relto))
(if (eq? base 'relative)
(or (current-load-relative-directory) (current-directory))
base))
relto))
submod)]
[(pair? relto) (values relto submod)]
[(not dir?)
(values
(and path?
(error 'resolve-module-path-index
"can't resolve \"self\" with non-path relative-to: ~e" relto))
submod)]
[(procedure? relto) (force-relto (relto) dir? #:path? path?)]
[else (values (and path? (current-directory)) submod)])))
(define (path-ss->rkt p)
(let-values ([(base name dir?) (split-path p)])
(if (regexp-match #rx"[.]ss$" (path->bytes name))
(path-replace-suffix p #".rkt")
p)))
(define (combine-submod v p)
(if (null? p)
v
(list* 'submod v p)))
(define (flatten base orig-p)
(let loop ([accum '()] [p orig-p])
(cond
[(null? p) (combine-submod base (reverse accum))]
[(equal? (car p) "..")
(if (null? accum)
(error 'resolve-module-path "too many \"..\"s: ~s"
(combine-submod base orig-p))
(loop (cdr accum) (cdr p)))]
[else (loop (cons (car p) accum) (cdr p))])))
(define (resolve-module-path s relto)
;; relto should be a complete path, #f, or procedure that returns a
;; complete path
(define (get-dir) (force-relto relto #t))
(cond [(symbol? s)
;; use resolver handler:
(resolved-module-path-name
(module-path-index-resolve
(module-path-index-join s #f)))]
[(string? s)
;; Parse Unix-style relative path string
(define-values (dir submod) (get-dir))
(combine-submod
(path-ss->rkt
(apply build-path dir (explode-relpath-string s)))
submod)]
[(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 (expand-user-path (cadr s)))])
(define-values (d submod) (get-dir))
(combine-submod
(path-ss->rkt
(path->complete-path
p
(if (path-string? d)
d
(or (current-load-relative-directory)
(current-directory)))))
submod))]
[(or (eq? (car s) 'lib)
(eq? (car s) 'quote)
(eq? (car s) 'planet))
;; use resolver handler in this case, too:
(define-values (d submod) (force-relto relto #f #:path? #f))
(combine-submod
(resolved-module-path-name
(module-path-index-resolve
(module-path-index-join s #f)))
submod)]
[(eq? (car s) 'submod)
(define r (cond
[(or (equal? (cadr s) ".")
(equal? (cadr s) ".."))
(define-values (d submod) (force-relto relto #f))
(combine-submod d submod)]
[else (resolve-module-path (cadr s) relto)]))
(define base-submods (if (and (or (equal? (cadr s) ".")
(equal? (cadr s) ".."))
(pair? r))
(cddr r)
null))
(define base (if (pair? r) (cadr r) r))
(flatten base (append base-submods
(if (equal? (cadr s) "..") (cdr s) (cddr s))))]
[else #f]))
(define (resolve-module-path-index mpi relto)
;; relto must be a complete path
(let-values ([(path base) (module-path-index-split mpi)])
(if path
(resolve-module-path path (resolve-possible-module-path-index base relto))
(let ()
(define sm (module-path-index-submodule mpi))
(define-values (dir submod) (force-relto relto #f))
(combine-submod (path-ss->rkt dir) (if (and sm submod)
(append submod sm)
(or sm submod)))))))
(define (resolve-possible-module-path-index base relto)
(cond [(module-path-index? base)
(resolve-module-path-index base relto)]
[(and (resolved-module-path? base)
(path? (resolved-module-path-name base)))
(resolved-module-path-name base)]
[relto relto]
[else #f]))
(define rel-to-path-string/c
(or/c path-string? (cons/c 'submod (cons/c path-string? (listof symbol?)))))
(define rel-to-path-string/thunk/#f
(or/c rel-to-path-string/c (-> rel-to-path-string/c) false/c))
(provide/contract
[resolve-module-path (module-path?
rel-to-path-string/thunk/#f
. -> . (or/c path? symbol?
(cons/c 'submod (cons/c (or/c path? symbol?)
(listof symbol?)))))]
[resolve-module-path-index ((or/c symbol? module-path-index?)
rel-to-path-string/thunk/#f
. -> . (or/c path? symbol?
(cons/c 'submod (cons/c (or/c path? symbol?)
(listof symbol?)))))])