added rename option to lazy-require

closes PR 13624

also added examples
This commit is contained in:
Ryan Culpepper 2013-03-24 18:05:41 -04:00
parent 2eae24b0b1
commit 1b729d34d8
2 changed files with 87 additions and 52 deletions

View File

@ -37,59 +37,71 @@
(define-syntax (lazy-require1 stx) (define-syntax (lazy-require1 stx)
(syntax-case stx () (syntax-case stx ()
[(lazy-require1 modpath (name ...) orig-stx) [(lazy-require1 modpath (thing ...) orig-stx)
(with-syntax ([(defn ...) (with-syntax ([((exp-name bind-name) ...)
(for/list ([name (in-list (syntax->list #'(name ...)))]) (for/list ([thing-stx (in-list (syntax->list #'(thing ...)))])
(unless (identifier? name) (syntax-case thing-stx ()
(raise-syntax-error #f "expected identifier" #'orig-stx name)) [name
(with-syntax ([name name] (identifier? #'name)
[(aux) (generate-temporaries (list name))]) (list #'name #'name)]
#`(begin (define aux (make-lazy-function 'name get-sym)) [[exp-name bind-name]
(define-syntax name (begin
(make-rename-transformer (unless (identifier? #'exp-name)
(syntax-property (quote-syntax aux) (raise-syntax-error #f "expected identifier"
'not-provide-all-defined #t))))))] #'orig-stx #'exp-name))
[define-mpi-var (unless (identifier? #'bind-name)
(let ([phase (sub1 (variable-reference->phase (#%variable-reference)))]) (raise-syntax-error #f "expected identifier"
(if (zero? phase) #'orig-stx #'bind-name))
;; `define-runtime-module-path-index' works right at phase-level 0: (list #'exp-name #'bind-name))]
#'(define-runtime-module-path-index mpi-var (quote modpath)) [_
;; need a submodule: (raise-syntax-error #f "expected identifier or pair of identifiers"
(with-syntax ([lazy-require-path-n #'orig-stx thing-stx)]))]
(string->symbol [mpi-var-defn
(format "lazy-require-path-~a-~a" (let ([phase (sub1 (variable-reference->phase (#%variable-reference)))])
phase (if (zero? phase)
counter))] ;; `define-runtime-module-path-index' works right at phase-level 0:
;; May need to adjust modpath, since we're interpreting it #'(define-runtime-module-path-index mpi-var (quote modpath))
;; relative to a *submodule* of the original context. ;; need a submodule:
;; ie, module-path interpretation is not hygienic! (with-syntax ([lazy-require-path-n
[modpath* (module-path-add-submod-up #'modpath)]) (string->symbol
(set! counter (add1 counter)) (format "lazy-require-path-~a-~a"
#'(begin phase
(module lazy-require-path-n racket/base counter))]
(require racket/runtime-path ;; May need to adjust modpath, since we're interpreting it
(for-syntax racket/base)) ;; relative to a *submodule* of the original context.
(provide mpi-var) ;; ie, module-path interpretation is not hygienic!
(define-runtime-module-path-index mpi-var (quote modpath*))) [modpath* (module-path-add-submod-up #'modpath)])
(require 'lazy-require-path-n)))))]) (set! counter (add1 counter))
#'(begin #'(begin
define-mpi-var (module lazy-require-path-n racket/base
(define (get-sym sym) (require racket/runtime-path
(parameterize ((current-namespace (variable-reference->namespace (#%variable-reference)))) (for-syntax racket/base))
(begin0 (provide mpi-var)
(dynamic-require mpi-var sym) (define-runtime-module-path-index mpi-var (quote modpath*)))
(do-registration (#%variable-reference) (quote modpath))))) (require (submod "." lazy-require-path-n))))))])
defn ...))])) (with-syntax ([(aux-name ...) (generate-temporaries #'(bind-name ...))])
#'(begin
mpi-var-defn
(define (get-sym sym)
(parameterize ((current-namespace (variable-reference->namespace (#%variable-reference))))
(begin0
(dynamic-require mpi-var sym)
(do-registration (#%variable-reference) (quote modpath)))))
(define aux-name (make-lazy-function 'exp-name 'bind-name get-sym)) ...
(define-syntax bind-name
(make-rename-transformer
(syntax-property (quote-syntax aux-name)
'not-provide-all-defined #t))) ...)))]))
(define (make-lazy-function name get-sym) (define (make-lazy-function exp-name bind-name get-sym)
;; Use 'delay/sync' because 'delay' promise is not reentrant. ;; Use 'delay/sync' because 'delay' promise is not reentrant.
;; FIXME: OTOH, 'delay/sync' promise is not kill-safe. ;; FIXME: OTOH, 'delay/sync' promise is not kill-safe.
(let ([fun-p (delay/sync (get-sym name))]) (let ([fun-p (delay/sync (get-sym exp-name))])
(procedure-rename (procedure-rename
(make-keyword-procedure (make-keyword-procedure
(lambda (kws kwargs . args) (lambda (kws kwargs . args)
(keyword-apply (force fun-p) kws kwargs args))) (keyword-apply (force fun-p) kws kwargs args)))
name))) bind-name)))
(define (do-registration vr modpath) (define (do-registration vr modpath)
(let ([path (resolved-module-path-name (let ([path (resolved-module-path-name

View File

@ -2824,12 +2824,19 @@ heuristics, and should only be used when other inlining attempts (such as
@note-lib-only[racket/lazy-require] @note-lib-only[racket/lazy-require]
@defform[(lazy-require [module-path (imported-fun-id ...)] ...)]{ @(define lazy-require-eval (make-base-eval))
@(lazy-require-eval '(require racket/lazy-require))
Defines each @racket[imported-fun-id] as a function that, when called, @defform[(lazy-require [module-path (fun-import ...)] ...)
dynamically requires the export named @racket[imported-fun-id] from #:grammar
the module specified by @racket[module-path] and calls it with the ([fun-import fun-id
same arguments. (orig-fun-id fun-id)])]{
Defines each @racket[fun-id] as a function that, when called,
dynamically requires the export named @racket[orig-fun-id] from the
module specified by @racket[module-path] and calls it with the same
arguments. If @racket[orig-fun-id] is not given, it defaults to
@racket[fun-id].
If the enclosing relative phase level is not 0, then If the enclosing relative phase level is not 0, then
@racket[module-path] is also placed in a submodule (with a use of @racket[module-path] is also placed in a submodule (with a use of
@ -2841,4 +2848,20 @@ submodule). Introduced submodules have the names
When the use of a lazily-required function triggers module loading, When the use of a lazily-required function triggers module loading,
@racket[register-external-module] declares a potential compilation @racket[register-external-module] declares a potential compilation
dependency (in case the function is used in the process of compiling a dependency (in case the function is used in the process of compiling a
module).} module).
@examples[#:eval lazy-require-eval
(lazy-require
[racket/list (partition)])
(partition even? '(1 2 3 4 5))
(module hello racket/base
(provide hello)
(printf "starting hello server\n")
(define (hello) (printf "hello!\n")))
(lazy-require
['hello ([hello greet])])
(greet)
]
}
@(close-eval lazy-require-eval)