Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The goal is to eliminate situations where you're plopped at the start of a file because we couldn't find the definition location within the file. - Racket's `identifier-binding` returns two symbol/file answers -- "plain" and "nominal". Use `for/or` to try each uniformly until we find an answer. ("Try" means looking for a symbol that `identifier-binding` directly gave us, as well as the case where it doesn't due to a provide involving both a contract and a rename.) - Add a hack to compensate for definer macros that don't provide source location for the definition syntax: If the parent syntax does, use its location. (A definer macro ought to use `syntax/loc` or the `#:source` argument to `format-id`, to ensure that the identifier syntax has full source location. For macros that do not, at least now we can show the location of some macro syntax closely related to the definition, and hopefully nearby in the source file.) - More thorough tests.
- Loading branch information
Greg Hendershott
committed
Feb 27, 2017
1 parent
71fa4d6
commit c50cd48
Showing
4 changed files
with
200 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#lang racket/base | ||
|
||
(require racket/contract) | ||
|
||
;; For tests of defn.rkt. | ||
;; | ||
;; Until I can figure out how to make this work as a submodule of its | ||
;; `test` submodule. | ||
|
||
(define (plain x) x) | ||
(provide plain) | ||
(provide (rename-out [plain renamed])) | ||
|
||
(define (contracted1 x) x) | ||
(provide (contract-out [contracted1 (-> any/c any)])) | ||
(define (contracted2 x) x) | ||
(provide/contract [contracted2 (-> any/c any)]) | ||
|
||
(define (c/r x) x) | ||
(provide (contract-out [rename c/r contracted/renamed (-> any/c any)])) | ||
|
||
(define-syntax-rule (plain-definer name) | ||
(begin | ||
(define (name x) x) | ||
(provide name))) | ||
(plain-definer plain-by-macro) | ||
|
||
(define-syntax-rule (contracted-definer name) | ||
(begin | ||
(define (name x) x) | ||
(provide (contract-out [name (-> any/c any)])))) | ||
(contracted-definer contracted-by-macro) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#lang at-exp racket/base | ||
|
||
(require racket/format | ||
racket/match | ||
racket/runtime-path | ||
rackunit | ||
syntax/modread | ||
"../defn.rkt" | ||
"defn-examples.rkt") | ||
|
||
(define-runtime-path dot-dot "..") | ||
|
||
(define-namespace-anchor nsa) | ||
(parameterize ([current-namespace (namespace-anchor->namespace nsa)]) | ||
(define (not-0 v) (not (= 0 v))) | ||
(define (not-1 v) (not (= 1 v))) | ||
|
||
(check-equal? (find-definition "display") | ||
'kernel) | ||
(check-equal? (find-signature "display") | ||
'("defined in #%kernel, signature unavailable")) | ||
|
||
(check-match (find-definition "displayln") | ||
(list (pregexp "/racket/private/misc\\.rkt$") | ||
(? not-1) | ||
(? not-0))) | ||
(check-equal? (find-signature "displayln") | ||
'((displayln v) (displayln v p))) ;case-lambda defn | ||
|
||
;; Test a definer macro that (as of Racket 6.7) does not properly | ||
;; set srcloc: Can we at least return a specfic location for its | ||
;; parent syntax (as opposed to line 1 column 0)? | ||
(check-match (find-definition "in-hash") | ||
(list (pregexp "/racket/private/for.rkt$") | ||
(? not-1) | ||
(? not-0))) | ||
|
||
;; Tests for specific locations in defn-examples.rkt | ||
|
||
(check-match (find-definition "plain") | ||
(list (pregexp "defn-examples.rkt$") 10 9)) | ||
(check-equal? (find-signature "plain") | ||
'(plain x)) | ||
|
||
(check-match (find-definition "renamed") | ||
(list (pregexp "defn-examples.rkt$") 10 9)) | ||
(check-equal? (find-signature "renamed") | ||
'(plain x)) | ||
|
||
(check-match (find-definition "contracted1") | ||
(list (pregexp "defn-examples.rkt$") 14 9)) | ||
(check-equal? (find-signature "contracted1") | ||
'(contracted1 x)) | ||
|
||
(check-match (find-definition "contracted2") | ||
(list (pregexp "defn-examples.rkt$") 16 9)) | ||
(check-equal? (find-signature "contracted2") | ||
'(contracted2 x)) | ||
|
||
(check-match (find-definition "contracted/renamed") | ||
(list (pregexp "defn-examples.rkt$") 19 9)) | ||
(check-equal? (find-signature "contracted/renamed") | ||
'(c/r x)) | ||
|
||
(check-match (find-definition "plain-by-macro") | ||
(list (pregexp "defn-examples.rkt$") 26 15)) | ||
(check-false (find-signature "plain-by-macro")) | ||
|
||
(check-match (find-definition "contracted-by-macro") | ||
(list (pregexp "defn-examples.rkt$") 32 20)) | ||
(check-false (find-signature "contracted-by-macro")) | ||
|
||
|
||
;; This is (roughly) a test of opening a Racket source file and | ||
;; doing M-. on every non-list sexpr: Call find-definition on each | ||
;; sexpr. Not-found (#f) is fine. But fail test for (list _ 1 0) -- | ||
;; i.e. the source file was found, but not the location within. | ||
(define (check-non-bof-location file) | ||
(define ht (make-hash)) | ||
(define (find k) ;memoized find-definition | ||
(hash-ref ht k | ||
(λ () | ||
(define v (find-definition (format "~a" k))) | ||
(hash-set! ht k v) | ||
v))) | ||
(define (walk v) | ||
(if (list? v) | ||
(for-each walk v) | ||
(match (find v) | ||
[(list where 1 0) | ||
(fail @~a{can't find definition of `@|v|` in @where})] | ||
[_ (void)]))) | ||
(walk | ||
(with-module-reading-parameterization | ||
;; Why read not read-syntax? Because we only care about the | ||
;; sexprs as text: `find-definition` takes a string, because | ||
;; `racket-visit-definition` takes text from an Emacs buffer. | ||
(λ () (with-input-from-file file read))))) | ||
(for ([file '("cmds.rkt" | ||
"run.rkt")]) | ||
(check-non-bof-location (build-path dot-dot file)))) |