fix the way check syntax traverses #%require expressions that it sees

(the way things currently stand, check syntax needs more information
 from the fully expanded form, but at least now it has a better chance
 to actually use that information, if it were there ...)

related to PR 7815
related to PR 10455
related to PR 10788
This commit is contained in:
Robby Findler 2012-09-29 22:09:02 -05:00
parent 14e276094a
commit ce8d8eb763
2 changed files with 96 additions and 110 deletions

View File

@ -8,6 +8,7 @@
"xref.rkt"
string-constants
racket/unit
racket/match
racket/set
racket/class
racket/list
@ -313,71 +314,73 @@
(begin
(annotate-raw-keyword stx-obj varrefs)
(for-each (lambda (e) (level-loop e (+ level 1))) (syntax->list (syntax (exp ...)))))]
[(module m-name lang (#%plain-module-begin bodies ...))
(begin
(annotate-raw-keyword stx-obj varrefs)
(hash-set! module-lang-requires (syntax lang) #t)
((annotate-require-open user-namespace user-directory) (syntax lang))
(annotate-require-open user-namespace user-directory (syntax lang))
(hash-cons! requires (syntax->datum (syntax lang)) (syntax lang))
(for-each loop (syntax->list (syntax (bodies ...)))))]
[(module* m-name lang (#%plain-module-begin bodies ...))
(begin
(annotate-raw-keyword stx-obj varrefs)
(when (syntax-e #'lang)
(hash-set! module-lang-requires (syntax lang) #t)
((annotate-require-open user-namespace user-directory) (syntax lang))
(annotate-require-open user-namespace user-directory (syntax lang))
(hash-cons! requires (syntax->datum (syntax lang)) (syntax lang)))
(for-each loop (syntax->list (syntax (bodies ...)))))]
; top level or module top level only:
[(#%require require-specs ...)
(let ([at-phase
(lambda (stx level)
(define requires (hash-ref! phase-to-requires level (λ () (make-hash))))
(syntax-case stx ()
[(_ require-specs ...)
(with-syntax ([((require-specs ...) ...)
(map (lambda (spec)
(syntax-case spec (just-meta)
[(just-meta m spec ...)
#'(spec ...)]
[else (list spec)]))
(syntax->list #'(require-specs ...)))])
(let ([new-specs (map trim-require-prefix
(syntax->list (syntax (require-specs ... ...))))])
(annotate-raw-keyword stx-obj varrefs)
(for-each (annotate-require-open user-namespace
user-directory)
new-specs)
(for-each (add-require-spec requires)
new-specs
(syntax->list (syntax (require-specs ... ...))))))]))])
(for ([spec (in-list (syntax->list #'(require-specs ...)))])
[(#%require raw-require-specs ...)
(let ()
(define (handle-raw-require-spec spec)
(let loop ([spec spec]
[level level])
(define (add-to-level n) (and n level (+ n level)))
(syntax-case* spec (for-syntax for-template for-label for-meta just-meta)
(lambda (a b)
(eq? (syntax-e a) (syntax-e b)))
[(just-meta phase specs ...)
(for ([spec (in-list (syntax->list #'(specs ...)))])
(loop spec (add-to-level (syntax-e #'phase))))]
(syntax-case* spec (for-meta for-syntax for-template for-label just-meta) sym-eq?
[(for-meta phase specs ...)
(for ([spec (in-list (syntax->list #'(specs ...)))])
(loop spec (add-to-level (syntax-e #'phase))))]
[(for-syntax specs ...)
(at-phase spec (add-to-level 1))]
(for ([spec (in-list (syntax->list #'(specs ...)))])
(loop spec (add-to-level 1)))]
[(for-template specs ...)
(at-phase spec (add-to-level -1))]
(for ([spec (in-list (syntax->list #'(specs ...)))])
(loop spec (add-to-level -1)))]
[(for-label specs ...)
(at-phase spec #f)]
(for ([spec (in-list (syntax->list #'(specs ...)))])
(loop spec #f))]
[(just-meta phase specs ...)
(for ([spec (in-list (syntax->list #'(specs ...)))])
(handle-phaseless-spec spec (add-to-level (syntax-e #'phase))))]
[else
(at-phase (list #f spec) level)]))))]
(handle-phaseless-spec spec level)])))
(define (handle-phaseless-spec stx level)
(define require-ht (hash-ref! phase-to-requires level
(λ ()
(define h (make-hash))
(hash-set! phase-to-requires level h)
h)))
(define raw-module-path
(syntax-case* stx (only prefix all-expect prefix-all-except rename) sym-eq?
[(only raw-module-path id ...) #'raw-module-path]
[(prefix prefix-id raw-module-path) #'raw-module-path]
[(all-except raw-module-path id ...) #'raw-module-path]
[(prefix-all-except prefix-id raw-module-path id ...) #'raw-module-path]
[(rename raw-module-path local-id exported-id) #'raw-module-path]
[_ stx]))
(annotate-require-open user-namespace user-directory raw-module-path)
(when (syntax-original? raw-module-path)
(define key (syntax->datum raw-module-path))
(hash-set! require-ht
key
(cons stx (hash-ref require-ht key '())))))
(define (sym-eq? a b) (eq? (syntax-e a) (syntax-e b)))
(for ([spec (in-list (syntax->list #'(raw-require-specs ...)))])
(handle-raw-require-spec spec)))]
; module top level only:
[(#%provide provide-specs ...)
@ -434,21 +437,6 @@
[(identifier? prop)
(add-id id-set prop)])))))
;; add-require-spec : hash-table[sexp[require-spec] -o> (listof syntax)]
;; -> sexp[require-spec]
;; syntax
;; -> void
(define (add-require-spec require-ht)
(λ (raw-spec syntax)
(when (syntax-original? syntax)
(let ([key (syntax->datum raw-spec)])
(hash-set! require-ht
key
(cons syntax
(hash-ref require-ht
key
(λ () '()))))))))
;; annotate-variables : namespace directory string id-set[four of them] (listof syntax) (listof syntax) -> void
;; colors in and draws arrows for variables, according to their classifications
;; in the various id-sets
@ -472,10 +460,10 @@
;; (list src pos pos) -o> (cons number number)] ;; indicates the number of defs and uses at this spot
(define connections (make-hash))
(for ([(level hash) (in-hash phase-to-requires)])
(for ([(level requires) (in-hash phase-to-requires)])
(define new-hash (make-hash))
(hash-set! unused/phases level new-hash)
(for ([(k v) (in-hash hash)])
(for ([(k v) (in-hash requires)])
(hash-set! new-hash k #t)))
(for ([(level binders) (in-hash phase-to-binders)])
@ -605,44 +593,43 @@
[req-stxes (hash-ref requires req-path (λ () #f))])
(when req-stxes
(hash-remove! unused req-path)
(for-each (λ (req-stx)
(when (id/require-match? (syntax->datum var)
id
(syntax->datum req-stx))
(when id
(define filename (get-require-filename source-req-path user-namespace user-directory))
(when filename
(add-jump-to-definition
var
source-id
filename)))
(add-mouse-over var
(format
(string-constant cs-mouse-over-import)
(syntax-e var)
req-path))
(connect-syntaxes req-stx var actual?
(id-level phase-level var)
connections)))
req-stxes))))))))
(for ([req-stx (in-list req-stxes)])
(when (id/require-match? (syntax->datum var)
id
(syntax->datum req-stx))
(when id
(define filename (get-require-filename source-req-path user-namespace user-directory))
(when filename
(add-jump-to-definition
var
source-id
filename)))
(add-mouse-over var
(format
(string-constant cs-mouse-over-import)
(syntax-e var)
req-path))
(connect-syntaxes req-stx var actual?
(id-level phase-level var)
connections))))))))))
(define (id/require-match? var id req-stx)
(cond
[(and (pair? req-stx)
(eq? (list-ref req-stx 0) 'prefix))
(let ([prefix (list-ref req-stx 1)])
(equal? (format "~a~a" prefix id)
(symbol->string var)))]
[(and (pair? req-stx)
(eq? (list-ref req-stx 0) 'prefix-all-except))
(let ([prefix (list-ref req-stx 1)])
(and (not (memq id (cdddr req-stx)))
(equal? (format "~a~a" prefix id)
(symbol->string var))))]
[(and (pair? req-stx)
(eq? (list-ref req-stx 0) 'rename))
(eq? (list-ref req-stx 2)
var)]
(match req-stx
[`(only ,_ . ,ids)
(and (memq id ids)
(eq? var id))]
[`(prefix ,prefix ,_)
(equal? (format "~a~a" prefix id)
(symbol->string var))]
[`(all-except ,_ . ,ids)
(and (eq? var id)
(not (member var ids)))]
[`(prefix-all-except ,prefix ,_ . ,rest)
(and (not (memq id rest))
(equal? (format "~a~a" prefix id)
(symbol->string var)))]
[`(rename ,_ ,local-id ,exported-id)
(eq? local-id var)]
[else (eq? var id)]))
@ -801,23 +788,22 @@
;; annotate-require-open : namespace string -> (stx -> void)
;; relies on current-module-name-resolver, which in turn depends on
;; current-directory and current-namespace
(define (annotate-require-open user-namespace user-directory)
(λ (require-spec)
(when (syntax-original? require-spec)
(let ([source (find-source-editor require-spec)])
(when (and source
(syntax-position require-spec)
(syntax-span require-spec))
(let ([defs-text (current-annotations)])
(when defs-text
(let* ([start (- (syntax-position require-spec) 1)]
[end (+ start (syntax-span require-spec))]
[file (get-require-filename (syntax->datum require-spec)
user-namespace
user-directory)])
(when file
(send defs-text syncheck:add-require-open-menu
source start end file))))))))))
(define (annotate-require-open user-namespace user-directory require-spec)
(when (syntax-original? require-spec)
(define source (find-source-editor require-spec))
(when (and source
(syntax-position require-spec)
(syntax-span require-spec))
(define defs-text (current-annotations))
(when defs-text
(define start (- (syntax-position require-spec) 1))
(define end (+ start (syntax-span require-spec)))
(define file (get-require-filename (syntax->datum require-spec)
user-namespace
user-directory))
(when file
(send defs-text syncheck:add-require-open-menu
source start end file))))))
;; get-require-filename : sexp-or-module-path-index namespace string[directory] -> filename or #f
;; finds the filename corresponding to the require in stx

View File

@ -757,8 +757,8 @@
("foldr" imported-variable)
(")" default-color))
(list '((10 18) (20 27))
'((28 51) (77 82) (83 88))
'((52 75) (77 82) (83 88))))
'((28 51) (83 88))
'((52 75) (77 82))))
(build-test "(module m mzscheme (require (prefix x: mzscheme)) x:+ +)"
'(("(" default-color)