racket/collects/scribblings/reference/module-reflect.scrbl
2008-01-03 19:07:02 +00:00

330 lines
14 KiB
Racket

#lang scribble/doc
@require["mz.ss"]
@title{Module Names and Loading}
@;------------------------------------------------------------------------
@section[#:tag "modnameresolver"]{Resolving Module Names}
The name of a declared module is represented by a @deftech{resolved
module path}, which encapsulates either a symbol or a complete
filesystem path (see @secref["pathutils"]). A symbol normally refers
to a predefined module or module declared through reflective
evaluation (e.g., @scheme[eval]). A filesystem path normally refers to
a module declaration that was loaded on demand via @scheme[require] or
other forms.
A @deftech{module path} is a datum that matches the grammar for
@scheme[_module-path] for @scheme[require]. A module path is relative
to another module.
@defproc[(resolved-module-path? [v any/c]) boolean?]{
Returns @scheme[#f] if @scheme[v] is a @tech{resolved module path},
@scheme[#f] otherwise.}
@defproc[(make-resolved-module-path [path (or/c symbol? (and/c path? complete-path?))])
resolved-module-path?]{
Returns a @tech{resolved module path} that encapsulates @scheme[path].
If @scheme[path] is not a symbol, it normally should be
@tech{cleanse}d (see @scheme[cleanse-path]) and simplified (see
@scheme[simplify-path]).
A @tech{resolved module path} is interned. That is, if two
@tech{resolved module path} values encapsulate paths that are
@scheme[equal?], then the @tech{resolved module path} values are
@scheme[eq?].}
@defproc[(resolved-module-path-name [module-path resolved-module-path?])
path?]{
Returns the path encapsulated by a @tech{resolved module path}.}
@defproc[(module-path? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] corresponds to a datum that matches
the grammar for @scheme[_module-path] for @scheme[require],
@scheme[#f] otherwise.}
@defparam[current-module-name-resolver proc
(case->
(resolved-module-path?
. -> .
any)
((or/c module-path? path?)
(or/c false/c resolved-module-path?)
(or/c false/c syntax?)
boolean?
. -> .
resolved-module-path?))]{
A parameter that determines the current @deftech{module name
resolver}, which manages the conversion from other kinds of module
references to a symbol or @tech{resolved module path}. For example,
when the expander encounters @scheme[(require _module-path)] where
@scheme[_module-path] is not an identifier, then the expander passes
@scheme['_module-path] to the module name resolver to obtain a symbol
or resolved module path. When such a @scheme[require] appears within a
module, the @deftech{module path resolver} is also given the name of
the enclosing module, so that a relative reference can be converted to
an absolute symbol or @tech{resolved module path}.
A @tech{module name resolver} takes one and four arguments:
%
@itemize{
@item{When given one argument, it is a name for a module declaration
that is already loaded. Such a call to the module name resolver is a
notification that the corresponding module does not need to be
loaded (for the current namespace, or any other namespace that
shares the same module registry). The module name resolver's result
is ignored.}
@item{When given four arguments, the first is a module path, either
equivalent to a quoted @scheme[module-path] for @scheme[require] or
a file system path. The second is name for the source module, if
any, to which the path is relative; f the second argument is
@scheme[#f], the module path is relative to @scheme[(or
(current-load-relative-directory) (current-directory))]. The third
argument is a @tech{syntax object} that can be used for error
reporting, if it is not @scheme[#f]. If the last argument is
@scheme[#t], then the module declaration should be loaded (if it is
not already), otherwise the module path should be simply resolved to
a name. The result is the resolved name.}
}
For the second case, the standard module name resolver keeps a
per-registry table of loaded module name. If a resolved module path is
not in the table, and @scheme[#f] is not provided as the third
argument to the @tech{module name resolver}, then the name is put into
the table and the corresponding file is loaded with a variant of
@scheme[load/use-compiled] that passes the expected module name to the
@tech{compiled-load handler}.
While loading a file, the default @tech{module name resolver} sets the
@scheme[current-module-declare-name] parameter to the resolved module
name. Also, the default @tech{module name resolver} records in a
private @tech{continuation mark} the filename being loaded, and it
checks whether such a mark already exists; if such a continuation mark
does exist in the current continuation, then the @exnraise[exn:fail]
with a message about a dependency cycle.
Module loading is suppressed (i.e., @scheme[#f] is supplied as a third
argument to the module name resolver) when resolving module paths in
@tech{syntax objects} (see @secref["stxobj-model"]). When a
@tech{syntax object} is manipulated, the current namespace might not
match the original namespace for the syntax object, and the module
should not necessarily be loaded in the current namespace.
The current module name resolver is called with a single argument by
@scheme[namespace-attach-module] to notify the resolver that a module
was attached to the current namespace (and should not be loaded in the
future for the namespace's registry). No other Scheme operation
invokes the module name resolver with a single argument, but other
tools (such as DrScheme) might call this resolver in this mode to
avoid redundant module loads.}
@defparam[current-module-declare-name name (or/c resolved-module-path? false/c)]{
A parameter that determines a module name that is used when evaluating
a @scheme[module] declaration (when the parameter value is not
@scheme[#f]). In that case, the @scheme[_id] from the @scheme[module]
declaration is ignored, and the parameter's value is used as the name
of the declared module.}
@;------------------------------------------------------------------------
@section[#:tag "modpathidx"]{Compiled Modules and References}
While expanding a @scheme[module] declaration, the expander resolves
module paths for imports to load module declarations as necessary and
to determine imported bindings, but the compiled form of a
@scheme[module] declaration preserves the original module path.
Consequently, a compiled module can be moved to another filesystem,
where the module name resolver can resolve inter-module references
among compiled code.
When a module reference is extracted from compiled form (see
@scheme[module-compiled-imports]) or from syntax objects in macro
expansion (see @secref["stxops"]), the module reference is reported in
the form of a @deftech{module path index}. A @tech{module path index}
is a semi-interned (multiple references to the same relative module
tend to use the same @tech{module path index} value, but not always)
opaque value that encodes a module path (see @scheme[module-path?])
and another @tech{module path index} to which it is relative.
A @tech{module path index} that uses both @scheme[#f] for its path and
base @tech{module path index} represents ``self''---i.e., the module
declaration that was the source of the @tech{module path index}---and
such a @tech{module path index} is always used as the root for a chain
of @tech{module path index}. For example, when extracting information
about an identifier's binding within a module, if the identifier is
bound by a definition within the same module, the identifier's source
module is reported using the ``self'' @tech{module path index}. If the
identifier is instead defined in a module that is imported via a
module path (as opposed to a literal module name), then the
identifier's source module will be reported using a @tech{module path
index} that contains the @scheme[require]d module path and the
``self'' @tech{module path index}.
A @tech{module path index} has state. When it is @deftech{resolved} to
a @tech{resolved module path}, then the @tech{resolved module path} is
stored with the @tech{module path index}. In particular, when a module
is loaded, its root @tech{module path index} is resolved to match the
module's declaration-time name. This resolved path is forgotten,
however, in identifiers that the module contributes to the compiled
and marshaled form of other modules. The transient nature of resolved
names allows the module code to be loaded with a different resolved
name than the name when it was compiled.
@defproc[(module-path-index? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a @tech{module path index},
@scheme[#f] otherwise.}
@defproc[(module-path-index-resolve [mpi module-path-index?])
resolved-module-path?]{
Returns a @tech{resolved module path} for the resolved module name,
computing the resolved name (and storing it in @scheme[mpi]) if it has
not been computed before.
Resolving a @tech{module path index} uses the current @tech{module
name resolver} (see @scheme[current-module-name-resolver]). Depending
on the kind of module paths encapsulated by @scheme[mpi], the computed
resolved name can depend on the value of
@scheme[current-load-relative-directory] or
@scheme[current-directory].}
@defproc[(module-path-index-split [mpi module-path-index?])
(values (or/c module-path? false/c)
(or/c module-path-index? false/c))]{
Returns two values: a module path, and a base @tech{module path index}
or @scheme[#f] to which the module path is relative.
A @scheme[#f] second result means that the path is relative to an
unspecified directory (i.e., its resolution depends on the value of
@scheme[current-load-relative-directory] and/or
@scheme[current-directory]).
A @scheme[#f] for the first result implies a @scheme[#f] for the
second result, and means that @scheme[mpi] represents ``self'' (see
above).}
@defproc[(module-path-index-join [path (or/c module-path? false/c)]
[mpi (or/c module-path-index? false/c)])
module-path-index?]{
Combines @scheme[path] and @scheme[mpi] to create a new @tech{module
path index}. The @scheme[path] argument can @scheme[#f] only if
@scheme[mpi] is also @scheme[false].}
@defproc[(compiled-module-expression? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a compiled @scheme[module]
declaration, @scheme[#f] otherwise. See also
@scheme[current-compile].}
@defproc[(module-compiled-name [compiled-module-code compiled-module-expression?])
symbol?]{
Takes a module declaration in compiled form and returns a symbol for
the module's declared name.}
@defproc[(module-compiled-imports [compiled-module-code compiled-module-expression?])
(values (listof module-path-index?)
(listof module-path-index?)
(listof module-path-index?)
(listof module-path-index?))]{
Takes a module declaration in compiled form and returns four values: a
list of module references for the module's explicit imports, a list of
module references for the module's explicit for-syntax imports, a list
of module references for the module's explicit for-template imports,
and a list of module references for the module's explicit for-label
imports.}
@defproc[(module-compiled-exports [compiled-module-code compiled-module-expression?])
(values list? list? list? list? list? list?)]{
Returns six lists: one for the module's explicit variable exports, one
for the module's explicit syntax exports, one for the module's
explicit @scheme[for-syntax] variable exports, one for the module's
explicit @scheme[for-syntax] syntax exports, one for the module's
explicit @scheme[for-label] variable exports, one for the module's
explicit @scheme[for-label] syntax exports.
Each list more precisely matches the contract
@schemeblock[
(listof (list/c symbol?
(listof
(or/c module-path-index?
(list/c module-path-index?
(one-of/c #f 'for-syntax 'for-label)
symbol?)))))
]
For each element of the list, the leading symbol is the name of the
export.
The second part---the list of @tech{module path index} values,
etc.---describes the origin of the exported identifier. If the origin
list is @scheme[null], then the exported identifier is defined in the
module. If the exported identifier is re-exported, instead, then the
origin list provides information on the import that was re-exported.
The origin list has more than one element if the binding was imported
multiple times from (possibly) different sources.
For each origin, a @tech{module path index} by itself means that the
binding was imported with a plain @scheme[require] (not
@scheme[for-syntax] or @scheme[for-label]), and imported identifier
has the same name as the re-exported name. An origin represented with
a list indicates explicitly the import, the import mode (plain
@scheme[require], @scheme[for-syntax], or @scheme[for-label]) and the
original export name of the re-exported binding.}
@;------------------------------------------------------------------------
@section[#:tag "dynreq"]{Dynamic Module Access}
@defproc[(dynamic-require [mod module-path?][provided (or/c symbol? false/c void?)])
any]{
Dynamically instantiates the module specified by @scheme[mod] for
@tech{phase} 0 in the current namespace's registry, if it is not yet
instantiated. If @scheme[mod] is not a symbol, the current
@tech{module name resolver} may load a module declaration to resolve
it (see @scheme[current-module-name-resolver]); the path is resolved
relative to @scheme[current-load-relative-directory] and/or
@scheme[current-directory].
If @scheme[provided] is @scheme[#f], then the result is
@|void-const|. Otherwise, when @scheme[provided] is a symbol, the
value of the module's export with the given name is returned. If the
module exports @scheme[provide] as syntax, then a use of the binding
is expanded and evaluated (in a fresh namespace to which the module is
attached). If the module has no such exported variable or syntax, or
if the variable is protected (see @secref["modprotect"]), the
@exnraise[exn:fail:contract].
If @scheme[provided] is @|void-const|, then the module is
@tech{visit}ed (see @secref["mod-parse"]), but not
@tech{instantiate}d. The result is @|void-const|.}
@defproc[(dynamic-require-for-syntax [mod module-path?]
[provided (or/c symbol? false/c)])
any]{
Like @scheme[dynamic-require], but in @tech{phase} 1.}