added begin-on-demand (combo of module* and lazy-require)
This commit is contained in:
parent
7bd1d5ed9b
commit
5d49663b83
|
@ -3,7 +3,8 @@
|
|||
compiler/cm-accomplice)
|
||||
racket/runtime-path
|
||||
racket/promise)
|
||||
(provide lazy-require)
|
||||
(provide lazy-require
|
||||
begin-on-demand)
|
||||
|
||||
(define-syntax (lazy-require stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -56,3 +57,58 @@
|
|||
(variable-reference->resolved-module-path vr))))])
|
||||
(when (path? path)
|
||||
(register-external-file path)))))
|
||||
|
||||
#|
|
||||
begin-on-demand notes/todo
|
||||
|
||||
Currently like lazy-require: only supports functions.
|
||||
|
||||
The #:export kw is clunky... one might think it would be nice to just
|
||||
re-use 'provide' syntax. Would get rename, prefix, etc for free. OTOH,
|
||||
might be misleading: might seem like provide should apply to
|
||||
*apparent* enclosing module, not module implicitly created by
|
||||
begin-on-demand.
|
||||
|
||||
Another nice idea would be to implement lazy-require in terms of
|
||||
begin-on-demand and real require. Unfortunately, that would mean we
|
||||
couldn't have cyclic lazy-requires, which is very useful.
|
||||
|#
|
||||
|
||||
(define-syntax (begin-on-demand stx)
|
||||
(syntax-case stx ()
|
||||
[(begin-on-demand #:export (exp ...) body ...)
|
||||
(with-syntax ([fresh-name (gensym 'on-demand-submodule)])
|
||||
#'(begin
|
||||
(module* fresh-name #f
|
||||
(no-provide body ...)
|
||||
(check-procedure exp 'exp) ...
|
||||
(provide exp ...))
|
||||
(define-namespace-anchor anchor)
|
||||
(define get-sym
|
||||
(let ([sub-mpi
|
||||
(module-path-index-join '(submod "." fresh-name)
|
||||
(variable-reference->resolved-module-path
|
||||
(#%variable-reference)))])
|
||||
(lambda (sym)
|
||||
(parameterize ((current-namespace (namespace-anchor->namespace anchor)))
|
||||
(dynamic-require sub-mpi sym)))))
|
||||
(define exp (make-lazy-function 'exp get-sym)) ...))]))
|
||||
|
||||
(define-syntax (no-provide stx)
|
||||
(syntax-case stx ()
|
||||
[(_ form)
|
||||
(let ([eform (local-expand #'form
|
||||
(syntax-local-context)
|
||||
#f)])
|
||||
(syntax-case eform (begin #%provide)
|
||||
[(begin e ...)
|
||||
#'(begin (no-provide e) ...)]
|
||||
[(#%provide . _)
|
||||
(raise-syntax-error #f "provide not allowed" eform)]
|
||||
[_ eform]))]
|
||||
[(_ form ...)
|
||||
#'(begin (no-provide form) ...)]))
|
||||
|
||||
(define (check-procedure x name)
|
||||
(unless (procedure? x)
|
||||
(error 'begin-on-demand "name bound on-demand is not a procedure: ~a" name)))
|
||||
|
|
|
@ -27,3 +27,20 @@ that computes a module path. As with
|
|||
@racket[define-runtime-module-path-index], a @racket[module-path-expr]
|
||||
is evaluated both in phase 0 and phase 1.
|
||||
}
|
||||
|
||||
@defform[(begin-on-demand #:export (fun-id ...)
|
||||
body ...+)]{
|
||||
|
||||
Defines each @racket[fun-id] as a function that, when called,
|
||||
dynamically loads and executes the @racket[body] forms. The
|
||||
@racket[body] forms must contain definitions for each @racket[fun-id],
|
||||
and the value of each @racket[fun-id] must be a function.
|
||||
|
||||
A @racket[body] form may be any module-level form except
|
||||
@racket[provide]. In particular, @racket[require] forms are allowed.
|
||||
|
||||
The @racket[body] forms are placed within a submodule that extends the
|
||||
scope of the enclosing module (ie, @racket[module*] with @racket[#f]
|
||||
in the language position). Consequently, any references to sibling
|
||||
submodules must include a with @racket[".."] module path element.
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user