racket/collects/syntax/modresolve.rkt
Matthew Flatt a6cfe3d5fb fix `resolve-module-path-index' when w.r.t. is submodule
A submodule path on the w.r.t. path was incorrectly (in most
cases) added to the resolved path.
2012-11-11 09:38:15 -07:00

148 lines
5.9 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))
(path-ss->rkt
(apply build-path dir (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 (expand-user-path (cadr s)))])
(define-values (d submod) (get-dir))
(path-ss->rkt
(path->complete-path
p
(if (path-string? d)
d
(or (current-load-relative-directory)
(current-directory))))))]
[(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))
(resolved-module-path-name
(module-path-index-resolve
(module-path-index-join s #f)))]
[(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?)))))])