diff --git a/collects/syntax/modcode.rkt b/collects/syntax/modcode.rkt index c36b94ac43..58ea911e11 100644 --- a/collects/syntax/modcode.rkt +++ b/collects/syntax/modcode.rkt @@ -165,7 +165,7 @@ c)) (raise (make-exn:get-module-code - (format "get-module-code: cannot find submodule: ~e" submodule-path) + (format "get-module-code: cannot find submodule: ~e" sm-path) (current-continuation-marks) #f))) (cdr sm-path))])) diff --git a/collects/tests/racket/embed-me21.rkt b/collects/tests/racket/embed-me21.rkt new file mode 100644 index 0000000000..dbf09c11cb --- /dev/null +++ b/collects/tests/racket/embed-me21.rkt @@ -0,0 +1,12 @@ +#lang racket/base +(require racket/match) + +;; check using `racket/match', particularly with a pattern +;; that eneds run-time support that may go through a +;; compile-time `lazy-require': + +(match "x" + [(pregexp "x") + (with-output-to-file "stdout" + (lambda () (printf "This is 21.\n")) + #:exists 'append)]) diff --git a/collects/tests/racket/embed.rktl b/collects/tests/racket/embed.rktl index 39da0cdd83..be3027b221 100644 --- a/collects/tests/racket/embed.rktl +++ b/collects/tests/racket/embed.rktl @@ -227,6 +227,7 @@ (one-mz-test "embed-me17.rkt" "This is 17.\n" #f) (one-mz-test "embed-me18.rkt" "This is 18.\n" #f) (one-mz-test "embed-me19.rkt" "This is 19.\n" #f) + (one-mz-test "embed-me21.rkt" "This is 21.\n" #f) ;; Try unicode expr and cmdline: (prepare dest "unicode") diff --git a/collects/unstable/lazy-require.rkt b/collects/unstable/lazy-require.rkt index 964c32f4ed..ca62b95197 100644 --- a/collects/unstable/lazy-require.rkt +++ b/collects/unstable/lazy-require.rkt @@ -1,6 +1,6 @@ #lang racket/base -(require (for-syntax racket/base - compiler/cm-accomplice) +(require (for-syntax racket/base) + compiler/cm-accomplice racket/runtime-path racket/promise) (provide lazy-require @@ -8,14 +8,21 @@ (define-syntax (lazy-require stx) (syntax-case stx () + [(lazy-require #:requires-for-path (extra-req ...) + [modpath (thing ...)] ...) + #`(begin + (lazy-require1 modpath (extra-req ...) (thing ...) #,stx) + ...)] [(lazy-require [modpath (thing ...)] ...) - #`(begin (define-namespace-anchor anchor) - (lazy-require1 modpath (thing ...) anchor #,stx) - ...)])) + (syntax/loc stx + (lazy-require #:requires-for-path () + [modpath (thing ...)] ...))])) + +(define-for-syntax counter 0) (define-syntax (lazy-require1 stx) (syntax-case stx () - [(lazy-require1 modpath (name ...) anchor orig-stx) + [(lazy-require1 modpath (extra-req ...) (name ...) orig-stx) (with-syntax ([(defn ...) (for/list ([name (in-list (syntax->list #'(name ...)))]) (unless (identifier? name) @@ -26,17 +33,37 @@ (define-syntax name (make-rename-transformer (syntax-property (quote-syntax aux) - 'not-provide-all-defined #t))))))]) + 'not-provide-all-defined #t))))))] + [define-mpi-var + (let ([phase (sub1 (variable-reference->phase (#%variable-reference)))]) + (if (zero? phase) + ;; `define-runtime-module-path-index' works right at phase-level 0: + #'(define-runtime-module-path-index mpi-var (quasiquote modpath)) + ;; need a submodule: + (with-syntax ([lazy-require-path-n + (string->symbol + (format "lazy-require-path-~a-~a" + phase + counter))]) + (set! counter (add1 counter)) + #'(begin + (module lazy-require-path-n racket/base + (require racket/runtime-path + (for-syntax racket/base) + extra-req ...) + (provide mpi-var) + (define-runtime-module-path-index mpi-var (quasiquote modpath))) + (require 'lazy-require-path-n)))))]) ;; implicit quasiquote, so can use normal module-path syntax ;; or escape to compute a the module-path via expression - #'(begin (define-runtime-module-path-index mpi-var (quasiquote modpath)) - (define-values () - (let-syntax ([_ (do-registration (#%variable-reference) (quasiquote modpath))]) - (values))) - (define (get-sym sym) - (parameterize ((current-namespace (namespace-anchor->namespace anchor))) - (dynamic-require mpi-var sym))) - defn ...))])) + #'(begin + define-mpi-var + (define (get-sym sym) + (parameterize ((current-namespace (variable-reference->namespace (#%variable-reference)))) + (begin0 + (dynamic-require mpi-var sym) + (do-registration (#%variable-reference) (quasiquote modpath))))) + defn ...))])) (define (make-lazy-function name get-sym) ;; Use 'delay/sync' because 'delay' promise is not reentrant. @@ -48,15 +75,14 @@ (keyword-apply (force fun-p) kws kwargs args))) name))) -(begin-for-syntax - (define (do-registration vr modpath) - (let ([path (resolved-module-path-name - (module-path-index-resolve - (module-path-index-join - modpath - (variable-reference->resolved-module-path vr))))]) - (when (path? path) - (register-external-file path))))) +(define (do-registration vr modpath) + (let ([path (resolved-module-path-name + (module-path-index-resolve + (module-path-index-join + modpath + (variable-reference->resolved-module-path vr))))]) + (when (path? path) + (register-external-module path)))) #| begin-on-demand notes/todo diff --git a/collects/unstable/scribblings/lazy-require.scrbl b/collects/unstable/scribblings/lazy-require.scrbl index 4e887b8b70..358becb7ff 100644 --- a/collects/unstable/scribblings/lazy-require.scrbl +++ b/collects/unstable/scribblings/lazy-require.scrbl @@ -3,7 +3,8 @@ "utils.rkt" (for-label racket/base racket/runtime-path - unstable/lazy-require)) + unstable/lazy-require + compiler/cm-accomplice)) @title[#:tag "lazy-require"]{Lazy Require} @unstable[@author+email["Ryan Culpepper" "ryanc@racket-lang.org"]] @@ -11,9 +12,12 @@ @defmodule[unstable/lazy-require] @defform/subs[#:literals (unquote) - (lazy-require [mod (imported-fun-id ...)] ...) + (lazy-require maybe-requires + [mod (imported-fun-id ...)] ...) ([mod module-path - (unquote module-path-expr)]) + (unquote module-path-expr)] + [maybe-requires code:blank + (code:line #:requires-for-path (require-spec ...))]) #:contracts ([module-path-expr module-path?])]{ Defines each @racket[imported-fun-id] as a function that, when called, @@ -25,8 +29,23 @@ The module @racket[mod] can be specified as a @racket[_module-path] (see @racket[require]) or as an @racket[unquote]-escaped expression 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. -} +is evaluated both in phase level 0 and phase level 1 relative to its +enclosing phase level. + +If the enclosing relative phase level is not 0, then +@racket[module-path-expr] is also placed in a submodule (with a use of +@racket[define-runtime-module-path-index] at phase level 0 within the +submodule); supply extra @racket[require-spec]s with +@racket[#:requires-for-path] to bind within the submodule for +@racket[module-path-expr]. Introduced submodules have the names +@racket[lazy-require-]@racket[_n]@racketidfont{-}@racket[_m], where +@racket[_n] is a phase-level number and @racket[_m] is a number. + +When the use of a lazily-required function triggers module loading, +@racket[register-external-module] declares a potential compilation +dependency (in case the function is used in the process of compiling a +module).} + @defform[(begin-on-demand #:export (fun-id ...) body ...+)]{