
Macros and other tools that need syntax privilege used `(current-code-inspector)' at the module top-level to try to capture the right code inspector at load time. It's more consistent to instead use the enclosing module's declaration-time inspector, and `var-ref->mod-decl-insp' provides that. The new function works only on references to anonymous variables, which limits access to the inspector. The real function name is longer, of course.
435 lines
17 KiB
Racket
435 lines
17 KiB
Racket
#lang scribble/doc
|
|
@(require "mz.rkt")
|
|
|
|
@title[#:tag "Namespaces"]{Namespaces}
|
|
|
|
See @secref["namespace-model"] for basic information on the
|
|
@tech{namespace} model.
|
|
|
|
A new @tech{namespace} is created with procedures like
|
|
@racket[make-empty-namespace], and @racket[make-base-namespace], which
|
|
return a first-class namespace value. A namespace is used by setting
|
|
the @racket[current-namespace] parameter value, or by providing the
|
|
namespace to procedures such as @racket[eval] and
|
|
@racket[eval-syntax].
|
|
|
|
@defproc[(namespace? [v any/c]) boolean?]{
|
|
|
|
Returns @racket[#t] if @racket[v] is a namespace value, @racket[#f]
|
|
otherwise.}
|
|
|
|
|
|
@defproc[(make-empty-namespace) namespace?]{
|
|
|
|
Creates a new namespace that is empty, and whose @tech{module
|
|
registry} contains no mappings. The namespace's @tech{base phase} is
|
|
the same as the @tech{base phase} of the @tech{current
|
|
namespace}. Attach modules from an existing namespace to the new one
|
|
with @racket[namespace-attach-module].}
|
|
|
|
|
|
@defproc[(make-base-empty-namespace) namespace?]{
|
|
|
|
Creates a new empty namespace, but with @racketmodname[racket/base]
|
|
attached. The namespace's @tech{base phase} is the same as the
|
|
@tech{phase} in which the @racket[make-base-empty-namespace]
|
|
function was created.}
|
|
|
|
|
|
@defproc[(make-base-namespace) namespace?]{
|
|
|
|
Creates a new namespace with @racketmodname[racket/base] attached and
|
|
@racket[require]d into the top-level environment. The namespace's
|
|
@tech{base phase} is the same as the @tech{phase} in which the
|
|
@racket[make-base-namespace] function was created.}
|
|
|
|
|
|
@defform[(define-namespace-anchor id)]{
|
|
|
|
Binds @racket[id] to a namespace anchor that can be used with
|
|
@racket[namespace-anchor->empty-namespace] and
|
|
@racket[namespace-anchor->namespace].
|
|
|
|
This form can be used only in a @tech{top-level context} or in a
|
|
@tech{module-context}.}
|
|
|
|
|
|
@defproc[(namespace-anchor? [v any/c]) boolean?]{
|
|
|
|
Returns @racket[#t] if @racket[v] is a namespace-anchor value,
|
|
@racket[#f] otherwise.}
|
|
|
|
|
|
@defproc[(namespace-anchor->empty-namespace [a namespace-anchor?]) namespace?]{
|
|
|
|
Returns an empty namespace that shares a @tech{module registry} with
|
|
the source of the anchor, and whose @tech{base phase} the
|
|
@tech{phase} in which the anchor was created.
|
|
|
|
If the anchor is from a @racket[define-namespace-anchor] form in a
|
|
module context, then the source is the namespace in which the
|
|
containing module is instantiated. If the anchor is from a
|
|
@racket[define-namespace-anchor] form in a top-level content, then the
|
|
source is the namespace in which the anchor definition was evaluated.}
|
|
|
|
|
|
@defproc[(namespace-anchor->namespace [a namespace-anchor?]) namespace?]{
|
|
|
|
Returns a namespace corresponding to the source of the anchor.
|
|
|
|
If the anchor is from a @racket[define-namespace-anchor] form in a
|
|
module context, then the result is a namespace for the module's body
|
|
in the anchor's phase. The result is the same as a namespace obtained
|
|
via @racket[module->namespace].
|
|
|
|
If the anchor is from a @racket[define-namespace-anchor] form in a
|
|
top-level content, then the result is the namespace in which the
|
|
anchor definition was evaluated.}
|
|
|
|
|
|
@defparam[current-namespace n namespace?]{
|
|
|
|
A parameter that determines the @techlink{current namespace}.}
|
|
|
|
|
|
@defproc[(namespace-symbol->identifier [sym symbol?]) identifier?]{
|
|
|
|
Similar to @racket[datum->syntax] restricted to symbols. The
|
|
@tech{lexical information} of the resulting identifier corresponds to
|
|
the top-level environment of the current namespace; the identifier has
|
|
no source location or properties.}
|
|
|
|
|
|
@defproc[(namespace-base-phase [namespace namespace? (current-namespace)]) exact-integer?]{
|
|
|
|
Returns the @tech{base phase} of @racket[namespace].}
|
|
|
|
|
|
@defproc[(namespace-module-identifier [where (or/c namespace? exact-integer? #f)
|
|
(current-namespace)])
|
|
identifier?]{
|
|
|
|
Returns an identifier whose binding is @racket[module] in the
|
|
@tech{base phase} of @racket[where] if it is a namespace, or in the
|
|
@racket[where] @tech{phase level} otherwise.
|
|
|
|
The @tech{lexical information} of the identifier includes bindings (in
|
|
the same @tech{phase level}) for all syntactic forms that appear in
|
|
fully expanded code (see @secref["fully-expanded"]), but using the
|
|
name reported by the second element of @racket[identifier-binding] for
|
|
the binding; the @tech{lexical information} may also include other
|
|
bindings.}
|
|
|
|
|
|
@defproc[(namespace-variable-value [sym symbol?]
|
|
[use-mapping? any/c #t]
|
|
[failure-thunk (or/c (-> any) #f) #f]
|
|
[namespace namespace? (current-namespace)])
|
|
any]{
|
|
|
|
Returns a value for @racket[sym] in @racket[namespace], using
|
|
@racket[namespace]'s @tech{base phase}. The returned value depends on
|
|
@racket[use-mapping?]:
|
|
|
|
@itemize[
|
|
|
|
@item{If @racket[use-mapping?] is true (the default), and if
|
|
@racket[sym] maps to a top-level variable or an imported variable
|
|
(see @secref["namespace-model"]), then the result is the same as
|
|
evaluating @racket[sym] as an expression. If @racket[sym] maps to
|
|
syntax or imported syntax, then @racket[failure-thunk] is called or
|
|
the @exnraise[exn:fail:syntax]. If @racket[sym] is mapped to an
|
|
undefined variable or an uninitialized module variable, then
|
|
@racket[failure-thunk] is called of the
|
|
@exnraise[exn:fail:contract:variable].}
|
|
|
|
@item{If @racket[use-mapping?] is @racket[#f], the namespace's
|
|
syntax and import mappings are ignored. Instead, the value of the
|
|
top-level variable named @racket[sym] in namespace is returned. If
|
|
the variable is undefined, then @racket[failure-thunk] is called or
|
|
the @exnraise[exn:fail:contract:variable].}
|
|
|
|
]
|
|
|
|
If @racket[failure-thunk] is not @racket[#f],
|
|
@racket[namespace-variable-value] calls @racket[failure-thunk] to
|
|
produce the return value in place of raising an
|
|
@racket[exn:fail:contract:variable] or @racket[exn:fail:syntax]
|
|
exception.}
|
|
|
|
|
|
@defproc[(namespace-set-variable-value! [sym symbol?]
|
|
[v any/c]
|
|
[map? any/c #f]
|
|
[namespace namespace? (current-namespace)])
|
|
void?]{
|
|
|
|
Sets the value of @racket[sym] in the top-level environment of
|
|
@racket[namespace] in the @tech{base phase}, defining @racket[sym] if
|
|
it is not already defined.
|
|
|
|
If @racket[map?] is supplied as true, then the namespace's
|
|
@tech{identifier} mapping is also adjusted (see
|
|
@secref["namespace-model"]) in the @tech{phase level} corresponding to
|
|
the @tech{base phase}, so that @racket[sym] maps to the variable.}
|
|
|
|
|
|
@defproc[(namespace-undefine-variable! [sym symbol?]
|
|
[namespace namespace? (current-namespace)])
|
|
void?]{
|
|
|
|
Removes the @racket[sym] variable, if any, in the top-level
|
|
environment of @racket[namespace] in its @tech{base phase}. The
|
|
namespace's @tech{identifier} mapping (see @secref["namespace-model"])
|
|
is unaffected.}
|
|
|
|
|
|
@defproc[(namespace-mapped-symbols [namespace namespace? (current-namespace)])
|
|
(listof symbol?)]{
|
|
|
|
Returns a list of all symbols that are mapped to variables, syntax,
|
|
and imports in @racket[namespace] for the @tech{phase level}
|
|
corresponding to the @tech{namespace}'s @tech{base phase}.}
|
|
|
|
|
|
|
|
@defproc[(namespace-require [quoted-raw-require-spec any/c])
|
|
void?]{
|
|
|
|
Performs the import corresponding to @racket[quoted-raw-require-spec]
|
|
in the top-level environment of the current namespace, like a
|
|
top-level @racket[#%require]. The @racket[quoted-raw-require-spec]
|
|
argument must be a datum that corresponds to a quoted
|
|
@racket[_raw-require-spec] for @racket[#%require], which includes
|
|
module paths.
|
|
|
|
Module paths in @racket[quoted-raw-require-spec] are resolved with respect
|
|
to @racket[current-load-relative-directory] or
|
|
@racket[current-directory] (if the former is @racket[#f]), even if the
|
|
current namespace corresponds to a module body.}
|
|
|
|
|
|
@defproc[(namespace-require/copy [quoted-raw-require-spec any/c])
|
|
void?]{
|
|
|
|
Like @racket[namespace-require] for syntax exported from the module,
|
|
but exported variables at the namespace's @tech{base phase} are
|
|
treated differently: the export's current value is copied to a
|
|
top-level variable in the current namespace.}
|
|
|
|
|
|
@defproc[(namespace-require/constant [quoted-raw-require-spec any/c])
|
|
void?]{
|
|
|
|
Like @racket[namespace-require], but for each exported variable at the
|
|
@tech{namespace}'s @tech{base phase}, the export's value is copied to
|
|
a corresponding top-level variable that is made immutable. Despite
|
|
setting the top-level variable, the corresponding identifier is bound
|
|
as imported.}
|
|
|
|
|
|
@defproc[(namespace-require/expansion-time [quoted-raw-require-spec any/c])
|
|
void?]{
|
|
|
|
Like @racket[namespace-require], but only the transformer part of the
|
|
module is executed relative to the @tech{namespace}'s @tech{base
|
|
phase}; that is, the module is merely @tech{visit}ed, and not
|
|
@tech{instantiate}d (see @secref["mod-parse"]). If the required module
|
|
has not been instantiated before, the module's variables remain
|
|
undefined.}
|
|
|
|
|
|
@defproc[(namespace-attach-module [src-namespace namespace?]
|
|
[modname module-path?]
|
|
[dest-namespace namespace? (current-namespace)])
|
|
void?]{
|
|
|
|
Attaches the instantiated module named by @racket[modname] in
|
|
@racket[src-namespace] (at its @tech{base phase}) to the @tech{module
|
|
registry} of @racket[dest-namespace]. If @racket[modname] is not a
|
|
symbol, the current module name resolver is called to resolve the
|
|
path, but no module is loaded; the resolved form of @racket[modname]
|
|
is used as the module name in @racket[dest-namespace]. In addition to
|
|
@racket[modname], every module that it imports (directly or
|
|
indirectly) is also recorded in the current namespace's @tech{module
|
|
registry}, and instances at the same @tech{phase} or lower are also
|
|
attached to @racket[dest-namespace] (while @tech{visits} at the
|
|
module's phase and instances at higher phases are not attached, nor
|
|
even made @tech{available} for on-demand @tech{visits}). The inspector
|
|
of the module invocation in @racket[dest-namespace] is the same as
|
|
inspector of the invocation in @racket[src-namespace].
|
|
|
|
If @racket[modname] does not refer to an @tech{instantiate}d module in
|
|
@racket[src-namespace], or if the name of any module to be attached
|
|
already has a different declaration or same-@tech{phase} instance in
|
|
@racket[dest-namespace], then the @exnraise[exn:fail:contract].
|
|
|
|
If @racket[src-namespace] and @racket[dest-namespace] do not have the
|
|
same @tech{base phase}, then the @exnraise[exn:fail:contract].}
|
|
|
|
|
|
@defproc[(namespace-attach-module-declaration [src-namespace namespace?]
|
|
[modname module-path?]
|
|
[dest-namespace namespace? (current-namespace)])
|
|
void?]{
|
|
|
|
Like @racket[namespace-attach-module], but the module
|
|
specified by @racket[modname] need only be declared (and not
|
|
necessarily @tech{instantiate}d) in @racket[src-namespace], and the
|
|
module is merely declared in @racket[dest-namespace].}
|
|
|
|
|
|
@defproc[(namespace-unprotect-module [inspector inspector?]
|
|
[modname module-path?]
|
|
[namespace namespace? (current-namespace)])
|
|
void?]{
|
|
|
|
Changes the inspector for the instance of the module referenced by
|
|
@racket[modname] in @racket[namespace]'s @tech{module registry} so
|
|
that it is controlled by the current code inspector. The given
|
|
@racket[inspector] must currently control the invocation of the module
|
|
in @racket[namespace]'s @tech{module registry}, otherwise the
|
|
@exnraise[exn:fail:contract]. See also @secref["modprotect"].}
|
|
|
|
|
|
@defproc[(namespace-module-registry [namespace namespace?])
|
|
any]{
|
|
|
|
Returns the @tech{module registry} of the given namespace. This value
|
|
is useful only for identification via @racket[eq?].}
|
|
|
|
|
|
@defproc[(module->namespace [modname module-path?]) namespace?]{
|
|
|
|
Returns a namespace that corresponds to the body of an instantiated
|
|
module in the current namespace's @tech{module registry} and in the
|
|
current namespace's @tech{base phase}, making the module at the
|
|
@tech{available} for on-demand @tech{visits} at the namespace's
|
|
@tech{base phase}. The returned namespace has the same @tech{module
|
|
registry} as the current namespace. Modifying a binding in the
|
|
namespace changes the binding seen in modules that require the
|
|
namespace's module.
|
|
|
|
Module paths in a top-level @racket[require] expression are resolved
|
|
with respect to the namespace's module. New @racket[provide]
|
|
declarations are not allowed.
|
|
|
|
If the current code inspector does not control the invocation of the
|
|
module in the current namespace's @tech{module registry}, the
|
|
@exnraise[exn:fail:contract]; see also @secref["modprotect"].
|
|
|
|
Bindings in the namespace cannot be modified if the
|
|
@racket[compile-enforce-module-constants] parameter was true when the
|
|
module was declared, unless the module declaration itself included
|
|
assignments to the binding via @racket[set!].}
|
|
|
|
|
|
@defproc[(namespace-syntax-introduce [stx syntax-object?]) syntax-object?]{
|
|
|
|
Returns a syntax object like @racket[stx], except that the current
|
|
namespace's bindings are included in the @tech{syntax object}'s
|
|
@tech{lexical information} (see @secref["stxobj-model"]). The
|
|
additional context is overridden by any existing @tech{top-level
|
|
bindings} in the @tech{syntax object}'s @tech{lexical information}, or
|
|
by any existing or future @tech{module bindings} in the @tech{lexical
|
|
information}.}
|
|
|
|
|
|
@defproc[(module-provide-protected? [module-path-index (or/c symbol? module-path-index?)]
|
|
[sym symbol?])
|
|
boolean?]{
|
|
|
|
Returns @racket[#f] if the module declaration for
|
|
@racket[module-path-index] defines @racket[sym] and exports it
|
|
unprotected, @racket[#t] otherwise (which may mean that the symbol
|
|
corresponds to an unexported definition, a protected export, or an
|
|
identifier that is not defined at all within the module).
|
|
|
|
The @racket[module-path-index] argument can be a symbol; see
|
|
@secref["modpathidx"] for more information on module path
|
|
indices.
|
|
|
|
Typically, the arguments to @racket[module-provide-protected?]
|
|
correspond to the first two elements of a list produced by
|
|
@racket[identifier-binding].}
|
|
|
|
|
|
@defproc[(variable-reference? [v any/c]) boolean?]{
|
|
|
|
Return @racket[#t] if @racket[v] is a @tech{variable reference}
|
|
produced by @racket[#%variable-reference], @racket[#f] otherwise.}
|
|
|
|
|
|
@defproc[(variable-reference-constant? [varref variable-reference?]) boolean?]{
|
|
|
|
Returns @racket[#t] if the variable represented by @racket[varref]
|
|
will retain its current value (i.e., @racket[varref] refers to a
|
|
variable that cannot be further modified by @racket[set!] or
|
|
@racket[define]), @racket[#f] otherwise.}
|
|
|
|
|
|
@defproc[(variable-reference->empty-namespace [varref variable-reference?])
|
|
namespace?]{
|
|
|
|
Returns an empty namespace that shares module declarations and
|
|
instances with the namespace in which @racket[varref] is instantiated,
|
|
and with the same phase as @racket[varref].}
|
|
|
|
|
|
@defproc[(variable-reference->namespace [varref variable-reference?])
|
|
namespace?]{
|
|
|
|
If @racket[varref] refers to a @tech{module-level variable}, then the
|
|
result is a namespace for the module's body in the referenced
|
|
variable's @tech{phase}; the result is the same as a namespace
|
|
obtained via @racket[module->namespace].
|
|
|
|
If @racket[varref] refers to a @tech{top-level variable}, then the
|
|
result is the namespace in which the referenced variable is defined.}
|
|
|
|
|
|
@defproc[(variable-reference->resolved-module-path [varref variable-reference?])
|
|
(or/c resolved-module-path? #f)]{
|
|
|
|
If @racket[varref] refers to a @tech{module-level variable}, the
|
|
result is a @tech{resolved module path} naming the module.
|
|
|
|
If @racket[varref] refers to a @tech{top-level variable}, then the
|
|
result is @racket[#f].}
|
|
|
|
@defproc[(variable-reference->module-source [varref variable-reference?])
|
|
(or/c symbol? (and/c path? complete-path?) #f)]{
|
|
|
|
If @racket[varref] refers to a @tech{module-level variable}, the
|
|
result is a path or symbol naming the module's source (which is
|
|
typically, but not always, the same as in the resolved module path).
|
|
|
|
If @racket[varref] refers to a @tech{top-level variable}, then the
|
|
result is @racket[#f].}
|
|
|
|
@defproc[(variable-reference->phase [varref variable-reference?])
|
|
exact-nonnegative-integer?]{
|
|
|
|
Returns the @tech{phase} of the variable referenced by @racket[varref].}
|
|
|
|
|
|
@defproc[(variable-reference->module-base-phase [varref variable-reference?])
|
|
exact-integer?]{
|
|
|
|
Returns the @tech{phase} in which the module is instantiated for the
|
|
variable referenced by @racket[varref], or @racket[0] if the variable
|
|
for @racket[varref] is not within a module.
|
|
|
|
For a variable with a module, the result is less than the result of
|
|
@racket[(variable-reference->phase varref)] by @math{n} when the
|
|
variable is bound at @tech{phase level} @math{n} within the module.}
|
|
|
|
|
|
@defproc[(variable-reference->module-declaration-inspector [varref variable-reference?])
|
|
inspector?]{
|
|
|
|
Returns the declaration @tech{inspector} (see @secref["modprotect"])
|
|
for the module of @racket[varref], where @racket[varref] must refer to
|
|
an anonymous module variable as produced by
|
|
@racket[(#%variable-reference)].}
|