Improve how multi-in assigns source location info for its expansion
This changes how multi-in is implemented so that the location for each expanded element in the final require spec is tied to the last relevant module path element. This allows DrRacket to intelligently show arrows linking each imported binding with a relevant piece of the multi-in import spec.
This commit is contained in:
parent
67e3899272
commit
dd97e7b72e
|
@ -1,6 +1,6 @@
|
|||
#lang racket/base
|
||||
|
||||
(require (for-syntax racket/base racket/require-transform racket/list
|
||||
(require (for-syntax racket/base racket/require-transform racket/list syntax/stx
|
||||
(only-in racket/syntax syntax-local-eval))
|
||||
"require-syntax.rkt")
|
||||
|
||||
|
@ -100,24 +100,26 @@
|
|||
|
||||
(define-for-syntax (multi xs)
|
||||
(define (loop xs)
|
||||
(if (null? xs)
|
||||
(if (stx-null? xs)
|
||||
'(())
|
||||
(let ([first (car xs)]
|
||||
[rest (loop (cdr xs))])
|
||||
(if (list? first)
|
||||
(let ([bads (filter list? first)])
|
||||
(let ([first (stx-car xs)]
|
||||
[rest (loop (stx-cdr xs))])
|
||||
(if (stx-list? first)
|
||||
(let ([bads (filter stx-list? (syntax->list first))])
|
||||
(if (null? bads)
|
||||
(append-map (λ (x) (map (λ (y) (cons x y)) rest)) first)
|
||||
(error 'multi-in "not a simple element" (car bads))))
|
||||
(append-map (λ (x) (map (λ (y) (cons x y)) rest)) (syntax->list first))
|
||||
(error 'multi-in "not a simple element" (car (syntax->datum bads)))))
|
||||
(map (λ (x) (cons first x)) rest)))))
|
||||
(define options (loop xs))
|
||||
(define (try pred? ->str str->)
|
||||
(and (andmap (λ (x) (andmap pred? x)) options)
|
||||
(and (andmap (λ (x) (andmap pred? (map syntax-e x))) options)
|
||||
(map (λ (x)
|
||||
(let ([r (apply string-append
|
||||
(add-between (if ->str (map ->str x) x)
|
||||
"/"))])
|
||||
(if str-> (str-> r) r)))
|
||||
(let* ([d (map syntax-e x)]
|
||||
[r (apply string-append
|
||||
(add-between (if ->str (map ->str d) d)
|
||||
"/"))]
|
||||
[ctxt (last x)])
|
||||
(datum->syntax ctxt (if str-> (str-> r) r) ctxt ctxt)))
|
||||
options)))
|
||||
(or (try string? #f #f)
|
||||
(try symbol? symbol->string string->symbol)
|
||||
|
@ -128,25 +130,25 @@
|
|||
(syntax-case stx ()
|
||||
[(_ elem0 elem ...)
|
||||
(quasisyntax/loc stx
|
||||
(combine-in #,@(datum->syntax stx (multi (syntax->datum #'(elem0 elem ...)))
|
||||
stx stx stx)))]))
|
||||
(combine-in #,@(multi #'(elem0 elem ...))))]))
|
||||
|
||||
|
||||
;; Tests for multi.
|
||||
;; We don't want to run them every time the file is required, so they are
|
||||
;; commented out. A proper test suite for racket/require should be written.
|
||||
;; (require tests/eli-tester)
|
||||
;; (test (multi '("a" "b" "c")) => '("a/b/c")
|
||||
;; (multi '("a" ("b" "c") "d")) => '("a/b/d" "a/c/d")
|
||||
;; (multi '("a" "b" ("c" "d"))) => '("a/b/c" "a/b/d")
|
||||
;; (multi '(("a" "b") "c" "d")) => '("a/c/d" "b/c/d")
|
||||
;; (multi '(("a" "b") ("c" "d"))) => '("a/c" "a/d" "b/c" "b/d")
|
||||
;; (multi '(("a" "b" "c" "d"))) => '("a" "b" "c" "d")
|
||||
;; (multi '(("a" "b" ("c" "d")))) =error> ""
|
||||
;; (multi '(a b c)) => '(a/b/c)
|
||||
;; (multi '(a (b c) d)) => '(a/b/d a/c/d)
|
||||
;; (multi '(a b (c d))) => '(a/b/c a/b/d)
|
||||
;; (multi '((a b) c d)) => '(a/c/d b/c/d)
|
||||
;; (multi '((a b) (c d))) => '(a/c a/d b/c b/d)
|
||||
;; (multi '((a b c d))) => '(a b c d)
|
||||
;; (multi '((a b (c d)))) =error> "")
|
||||
#;(begin-for-syntax
|
||||
(require tests/eli-tester)
|
||||
(test (map syntax-e (multi #'("a" "b" "c"))) => '("a/b/c")
|
||||
(map syntax-e (multi #'("a" ("b" "c") "d"))) => '("a/b/d" "a/c/d")
|
||||
(map syntax-e (multi #'("a" "b" ("c" "d")))) => '("a/b/c" "a/b/d")
|
||||
(map syntax-e (multi #'(("a" "b") "c" "d"))) => '("a/c/d" "b/c/d")
|
||||
(map syntax-e (multi #'(("a" "b") ("c" "d")))) => '("a/c" "a/d" "b/c" "b/d")
|
||||
(map syntax-e (multi #'(("a" "b" "c" "d")))) => '("a" "b" "c" "d")
|
||||
(map syntax-e (multi #'(("a" "b" ("c" "d"))))) =error> ""
|
||||
(map syntax-e (multi #'(a b c))) => '(a/b/c)
|
||||
(map syntax-e (multi #'(a (b c) d))) => '(a/b/d a/c/d)
|
||||
(map syntax-e (multi #'(a b (c d)))) => '(a/b/c a/b/d)
|
||||
(map syntax-e (multi #'((a b) c d))) => '(a/c/d b/c/d)
|
||||
(map syntax-e (multi #'((a b) (c d)))) => '(a/c a/d b/c b/d)
|
||||
(map syntax-e (multi #'((a b c d)))) => '(a b c d)
|
||||
(map syntax-e (multi #'((a b (c d))))) =error> ""))
|
||||
|
|
Loading…
Reference in New Issue
Block a user