racket/pkgs/racket-doc/scribblings/raco/zo-struct.scrbl

826 lines
37 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/core
(for-label racket/base
racket/contract
compiler/zo-structs
compiler/zo-parse
compiler/zo-marshal
compiler/decompile
racket/set))
@(define-syntax-rule (defstruct+ id fields . rest)
(defstruct id fields #:prefab . rest))
@title{Bytecode Representation}
@defmodule[compiler/zo-structs]
The @racketmodname[compiler/zo-structs] library defines the bytecode
structures that are produced by @racket[zo-parse] and consumed by
@racket[decompile] and @racket[zo-marshal].
@nested[#:style 'inset]{
@elem[#:style (style #f (list (background-color-property "yellow")))]{@bold{Warning:}}
The @racketmodname[compiler/zo-structs] library exposes internals
of the Racket bytecode abstraction. Unlike other Racket
libraries, @racketmodname[compiler/zo-structs] is subject to
incompatible changes across Racket versions.}
@defstruct+[zo ()]{
A supertype for all forms that can appear in compiled code.}
@; --------------------------------------------------
@section{Prefix}
@defstruct+[(compilation-top zo)
([max-let-depth exact-nonnegative-integer?]
[binding-namess (hash/c exact-nonnegative-integer?
(hash/c symbol? stx?))]
[prefix prefix?]
[code (or/c form? any/c)])]{
Wraps compiled code.
The @racket[max-let-depth] field indicates the
maximum stack depth that @racket[code] creates (not counting the
@racket[prefix] array).
The @racket[binding-namess] field provides a per-phase mapping from
symbols that appear in @racket[prefix] for top-level
@racket[def-values] forms and in top-level @racket[def-syntaxes]
forms. Each symbol is mapped to an identifier that will be bound
(after introduction into the namespace) by the definition.
The @racket[prefix] field describes top-level variables,
module-level variables, and quoted syntax-objects accessed by
@racket[code].
The @racket[code] field contains executable code; it is normally a
@racket[form], but a literal value is represented as itself.}
@defstruct+[(prefix zo)
([num-lifts exact-nonnegative-integer?]
[toplevels (listof (or/c #f symbol? global-bucket?
module-variable?))]
[stxs (listof (or stx? #f))]
[src-inspector-desc symbol?])]{
Represents a ``prefix'' that is pushed onto the stack to initiate
evaluation. The prefix is an array, where buckets holding the
values for @racket[toplevels] are first, then the buckets for the
@racket[stxs], then a bucket for another array if @racket[stxs] is
non-empty, then @racket[num-lifts] extra buckets for lifted local
procedures.
In @racket[toplevels], each element is one of the following:
@itemize[
@item{a @racket[#f], which indicates a dummy variable that is used
to access the enclosing module/namespace at run time;}
@item{a symbol, which is a reference to a variable defined in the
enclosing module;}
@item{a @racket[global-bucket], which is a top-level variable (appears
only outside of modules); or}
@item{a @racket[module-variable], which indicates a variable imported
from another module.}
]
The variable buckets and syntax objects that are recorded in a prefix
are accessed by @racket[toplevel] and @racket[topsyntax] expression
forms.
When an element of @racket[stxs] is @racket[#f], it coresponds to a
syntax object that was optimized away at the last minute. The slot
must not be referenced by a @racket[topsyntax] form.
The @racket[src-inspector-desc] field provides an inspector name that
is used within syntax-object bindings. At run time, the prefix gets
an inspector, and bindings that reference the same inspector name are
granted access capabilities through that inspector.}
@defstruct+[(global-bucket zo) ([name symbol?])]{
Represents a top-level variable, and used only in a
@racket[prefix]. Because modules cannot require top-level
variables, these will only appear in the top level
@racket[prefix]. Additionally, symbols in the top-level
prefix are an alias for @racket[global-bucket] structs,
making them redundant.}
@defstruct+[(module-variable zo)
([modidx module-path-index?]
[sym symbol?]
[pos exact-integer?]
[phase exact-nonnegative-integer?]
[constantness (or/c #f 'constant 'fixed
function-shape? struct-shape?)])]{
Represents a top-level variable, and used only in a @racket[prefix].
The @racket[pos] may record the variable's offset within its module,
or it can be @racket[-1] if the variable is always located by name.
The @racket[phase] indicates the phase level of the definition within
its module. The @racket[constantness] field is either @racket['constant],
a @racket[function-shape] value, or a @racket[struct-shape] value
to indicate that
variable's value is always the same for every instantiation of its module;
@racket['fixed] to indicate
that it doesn't change within a particular instantiation of the module;
or @racket[#f] to indicate that the variable's value
can change even for one particular instantiation of its module.}
@defstruct+[function-shape
([arity procedure-arity?]
[preserves-marks? boolean?])]{
Represents the shape of an expected import, which should be a function
having the arity specified by @racket[arity]. The
@racket[preserves-marks?] field is true if calling the function is
expected to leave continuation marks unchanged by the time it
returns.}
@deftogether[(
@defstruct+[struct-shape ()]
@defstruct+[(struct-type-shape struct-shape) ([field-count exact-nonnegative-integer?])]
@defstruct+[(constructor-shape struct-shape) ([arity exact-nonnegative-integer?])]
@defstruct+[(predicate-shape struct-shape) ()]
@defstruct+[(accessor-shape struct-shape) ([field-count exact-nonnegative-integer?])]
@defstruct+[(mutator-shape struct-shape) ([field-count exact-nonnegative-integer?])]
@defstruct+[(struct-type-property-shape struct-shape) ([has-guard? boolean?])]
@defstruct+[(property-predicate-shape struct-shape) ()]
@defstruct+[(property-accessor-shape struct-shape) ()]
@defstruct+[(struct-other-shape struct-shape) ()]
)]{
Represents the shape of an expected import as a structure-type
binding, constructor, etc.}
@defstruct+[(stx zo) ([content stx-obj?])]{
Wraps a syntax object as it appears in a @racket[prefix].}
@; --------------------------------------------------
@section{Forms}
@defstruct+[(form zo) ()]{
A supertype for all forms that can appear in compiled code (including
@racket[expr]s), except for literals that are represented as
themselves.}
@defstruct+[(def-values form)
([ids (listof toplevel?)]
[rhs (or/c expr? seq? inline-variant? any/c)])]{
Represents a @racket[define-values] form. Each element of
@racket[ids] will reference via the prefix either a top-level variable
or a local module variable.
After @racket[rhs] is evaluated, the stack is restored to its depth
from before evaluating @racket[rhs].}
@deftogether[(
@defstruct+[(def-syntaxes form) ([ids (listof symbol?)]
[rhs (or/c expr? seq? any/c)]
[prefix prefix?]
[max-let-depth exact-nonnegative-integer?]
[dummy (or/c toplevel? #f)])]
@defstruct+[(seq-for-syntax form)
([forms (listof (or/c form? any/c))]
[prefix prefix?]
[max-let-depth exact-nonnegative-integer?]
[dummy (or/c toplevel? #f)])]
)]{
Represents a @racket[define-syntaxes] or
@racket[begin-for-syntax] form. The @racket[rhs] expression or set of
@racket[forms] forms has its own @racket[prefix], which is pushed before evaluating
@racket[rhs] or the @racket[forms]; the stack is restored after obtaining the result values.
The @racket[max-let-depth] field indicates the maximum size of the
stack that will be created by @racket[rhs] (not counting
@racket[prefix]). The @racket[dummy] variable is used to access the enclosing
namespace.}
@defstruct+[(req form) ([reqs stx?]
[dummy toplevel?])]{
Represents a top-level @racket[#%require] form (but not one in a
@racket[module] form) with a sequence of specifications @racket[reqs].
The @racket[dummy] variable is used to access the top-level
namespace.}
@defstruct+[(seq form) ([forms (listof (or/c form? any/c))])]{
Represents a @racket[begin] form, either as an expression or at the
top level (though the latter is more commonly a @racket[splice] form).
When a @racket[seq] appears in an expression position, its
@racket[forms] are expressions.
After each form in @racket[forms] is evaluated, the stack is restored
to its depth from before evaluating the form.}
@defstruct+[(splice form) ([forms (listof (or/c form? any/c))])]{
Represents a top-level @racket[begin] form where each evaluation is
wrapped with a continuation prompt.
After each form in @racket[forms] is evaluated, the stack is restored
to its depth from before evaluating the form.}
@defstruct+[(inline-variant form) ([direct expr?]
[inline expr?])]{
Represents a function that is bound by @racket[define-values], where the
function has two variants.
The first variant is used for normal calls to the function. The second may
be used for cross-module inlining of the function.}
@defstruct+[(mod form)
([name (or/c symbol? (listof symbol?))]
[srcname symbol?]
[self-modidx module-path-index?]
[prefix prefix?]
[provides (listof (list/c (or/c exact-integer? #f)
(listof provided?)
(listof provided?)))]
[requires (listof (cons/c (or/c exact-integer? #f)
(listof module-path-index?)))]
[body (listof (or/c form? any/c))]
[syntax-bodies (listof (cons/c exact-positive-integer?
(listof (or/c def-syntaxes?
seq-for-syntax?))))]
[unexported (listof (list/c exact-nonnegative-integer?
(listof symbol?)
(listof symbol?)))]
[max-let-depth exact-nonnegative-integer?]
[dummy toplevel?]
[lang-info (or/c #f (vector/c module-path? symbol? any/c))]
[internal-context (or/c #f #t stx? (vectorof stx?))]
[binding-names (hash/c exact-integer?
(hash/c symbol? (or/c #t stx?)))]
[flags (listof (or/c 'cross-phase))]
[pre-submodules (listof mod?)]
[post-submodules (listof mod?)])]{
Represents a @racket[module] declaration.
The @racket[provides] and @racket[requires] lists are each an
association list from phases to exports or imports. In the case of
@racket[provides], each phase maps to two lists: one for exported
variables, and another for exported syntax. In the case of
@racket[requires], each phase maps to a list of imported module paths.
The @racket[body] field contains the module's run-time (i.e., phase
0) code. The @racket[syntax-bodies] list has a list of forms for
each higher phase in the module body; the phases are in order
starting with phase 1. The @racket[body] forms use @racket[prefix],
rather than any prefix in place for the module declaration itself,
while members of lists in @racket[syntax-bodies] have their own
prefixes. After each form in @racket[body] or @racket[syntax-bodies]
is evaluated, the stack is restored to its depth from before
evaluating the form.
The @racket[unexported] list contains lists of symbols for
unexported definitions that can be accessed through macro expansion
and that are implemented through the forms in @racket[body] and
@racket[syntax-bodies]. Each list in @racket[unexported] starts
with a phase level.
The @racket[max-let-depth] field indicates the maximum stack depth
created by @racket[body] forms (not counting the @racket[prefix]
array).
The @racket[dummy] variable is used to access the top-level
namespace.
The @racket[lang-info] value specifies an optional module path that
provides information about the module's implementation language.
The @racket[internal-context] value describes the lexical context of
the body of the module. This value is used by
@racket[module->namespace]. A @racket[#f] value means that the
context is unavailable or empty. A @racket[#t] value means that the
context is computed by re-importing all required modules. A
syntax-object value embeds lexical information; the syntax object
should contain a vector of two elements, where the first element of
the vector is a syntax object for the module's body, which includes
the outside-edge and inside-edge scopes, and the second element of
the vector is a syntax object that has just the module's inside-edge
scope.
The @racket[binding-names] value provides additional information to
@racket[module->namespace] to correlate symbol names for variables
and syntax definitions to identifiers that map to those variables. A
separate table of names exists for each phase, and a @racket[#t]
mapping for a name indicates that it is mapped but inaccessible
(because the relevant scopes are inaccessible).
The @racket[flags] field records certain properties of the module.
The @racket['cross-phase] flag indicates that the module body is
evaluated once and the results shared across instances for all phases; such a
module contains only definitions of functions, structure types, and
structure type properties.
The @racket[pre-submodules] field records @racket[module]-declared
submodules, while the @racket[post-submodules] field records
@racket[module*]-declared submodules.}
@defstruct+[(provided zo)
([name symbol?]
[src (or/c module-path-index? #f)]
[src-name symbol?]
[nom-src (or/c module-path-index? #f)]
[src-phase exact-nonnegative-integer?]
[protected? boolean?])]{
Describes an individual provided identifier within a @racket[mod]
instance.}
@; --------------------------------------------------
@section{Expressions}
@defstruct+[(expr form) ()]{
A supertype for all expression forms that can appear in compiled code,
except for literals that are represented as themselves and some
@racket[seq] structures (which can appear as an expression as long as
it contains only other things that can be expressions).}
@defstruct+[(lam expr)
([name (or/c symbol? vector?)]
[flags (listof (or/c 'preserves-marks 'is-method 'single-result
'only-rest-arg-not-used 'sfs-clear-rest-args))]
[num-params exact-nonnegative-integer?]
[param-types (listof (or/c 'val 'ref 'flonum 'fixnum 'extflonum))]
[rest? boolean?]
[closure-map (vectorof exact-nonnegative-integer?)]
[closure-types (listof (or/c 'val/ref 'flonum 'fixnum 'extflonum))]
[toplevel-map (or/c #f (set/c exact-nonnegative-integer?))]
[max-let-depth exact-nonnegative-integer?]
[body (or/c expr? seq? any/c)])]{
Represents a @racket[lambda] form. The @racket[name] field is a name
for debugging purposes. The @racket[num-params] field indicates the
number of arguments accepted by the procedure, not counting a rest
argument; the @racket[rest?] field indicates whether extra arguments
are accepted and collected into a ``rest'' variable. The
@racket[param-types] list contains @racket[num-params] symbols
indicating the type of each argumet, either @racket['val] for a normal
argument, @racket['ref] for a boxed argument (representing a mutable
local variable), @racket['flonum] for a flonum argument,
or @racket['extflonum] for an extflonum argument.
The
@racket[closure-map] field is a vector of stack positions that are
captured when evaluating the @racket[lambda] form to create a closure.
The @racket[closure-types] field provides a corresponding list of
types, but no distinction is made between normal values and boxed
values; also, this information is redundant, since it can be inferred
by the bindings referenced though @racket[closure-map].
When a closure captures top-level or module-level variables or
refers to a syntax-object constant, the variables and constants are
represented in the closure by capturing a prefix (in the sense
of @racket[prefix]). The @racket[toplevel-map] field indicates
which top-level and lifted variables are actually used by the
closure (so that variables in a prefix can be pruned by the run-time
system if they become unused) and whether any syntax objects are
used (so that the syntax objects as a group can be similarly
pruned). A @racket[#f] value indicates either that no prefix is
captured or all variables and syntax objects in the prefix should be
considered used. Otherwise, numbers in the set indicate which
variables and lifted variables are used. Variables are numbered
consecutively by position in the prefix starting from
@racket[0], but the number equal to the number of non-lifted
variables corresponds to syntax objects (i.e., the number is
include if any syntax-object constant is used). Lifted variables
are numbered immediately
afterward---which means that, if the prefix contains any syntax
objects, lifted-variable numbers are shifted down relative to a
@racket[toplevel] by the number of syntax object in the prefix
(which makes the @racket[toplevel-map] set more compact).
When the function is called, the rest-argument list (if any) is pushed
onto the stack, then the normal arguments in reverse order, then the
closure-captured values in reverse order. Thus, when @racket[body] is
run, the first value on the stack is the first value captured by the
@racket[closure-map] array, and so on.
The @racket[max-let-depth] field indicates the maximum stack depth
created by @racket[body] plus the arguments and closure-captured
values pushed onto the stack. The @racket[body] field is the
expression for the closure's body.
@history[#:changed "6.1.1.8" @elem{Added a number to
@racket[toplevel-map] to indicate whether any syntax object is used,
shifting numbers for lifted variables up by one if any syntax object
is in the prefix.}]}
@defstruct+[(closure expr)
([code lam?] [gen-id symbol?])]{
A @racket[lambda] form with an empty closure, which is a procedure
constant. The procedure constant can appear multiple times in the
graph of expressions for bytecode, and the @racket[code] field can be
a cycle for a recursive constant procedure; the @racket[gen-id] is
different for each such constant.}
@defstruct+[(case-lam expr) ([name (or/c symbol? vector?)]
[clauses (listof lam?)])]{
Represents a @racket[case-lambda] form as a combination of
@racket[lambda] forms that are tried (in order) based on the number of
arguments given.}
@defstruct+[(let-one expr)
([rhs (or/c expr? seq? any/c)]
[body (or/c expr? seq? any/c)]
[type (or/c #f 'flonum 'fixnum 'extflonum)]
[unused? boolean?])]{
Pushes an uninitialized slot onto the stack, evaluates @racket[rhs]
and puts its value into the slot, and then runs @racket[body]. If
@racket[type] is not @racket[#f], then @racket[rhs] must produce a
value of the corresponding type, and the slot must be accessed by @racket[localref]s that
expect the type. If @racket[unused?] is @racket[#t], then the slot
must not be used, and the value of @racket[rhs] is not actually pushed
onto the stack (but @racket[rhs] is constrained to produce a single
value).
After @racket[rhs] is evaluated, the stack is restored to its depth
from before evaluating @racket[rhs]. Note that the new slot is
created before evaluating @racket[rhs].}
@defstruct+[(let-void expr)
([count exact-nonnegative-integer?]
[boxes? boolean?]
[body (or/c expr? seq? any/c)])]{
Pushes @racket[count] uninitialized slots onto the stack and then runs
@racket[body]. If @racket[boxes?] is @racket[#t], then the slots are
filled with boxes that contain @|undefined-const|.}
@defstruct+[(install-value expr)
([count exact-nonnegative-integer?]
[pos exact-nonnegative-integer?]
[boxes? boolean?]
[rhs (or/c expr? seq? any/c)]
[body (or/c expr? seq? any/c)])]{
Runs @racket[rhs] to obtain @racket[count] results, and installs them
into existing slots on the stack in order, skipping the first
@racket[pos] stack positions. If @racket[boxes?] is @racket[#t], then
the values are put into existing boxes in the stack slots.
After @racket[rhs] is evaluated, the stack is restored to its depth
from before evaluating @racket[rhs].}
@defstruct+[(let-rec expr) ([procs (listof lam?)]
[body (or/c expr? seq? any/c)])]{
Represents a @racket[letrec] form with @racket[lambda] bindings. It
allocates a closure shell for each @racket[lambda] form in
@racket[procs], installs each onto the stack in previously allocated
slots in reverse order (so that the closure shell for the last element
of @racket[procs] is installed at stack position @racket[0]), fills
out each shell's closure (where each closure normally references some
other just-created closures, which is possible because the shells have
been installed on the stack), and then evaluates @racket[body].}
@defstruct+[(boxenv expr)
([pos exact-nonnegative-integer?]
[body (or/c expr? seq? any/c)])]{
Skips @racket[pos] elements of the stack, setting the slot afterward
to a new box containing the slot's old value, and then runs
@racket[body]. This form appears when a @racket[lambda] argument is
mutated using @racket[set!] within its body; calling the function
initially pushes the value directly on the stack, and this form boxes
the value so that it can be mutated later.}
@defstruct+[(localref expr)
([unbox? boolean?]
[pos exact-nonnegative-integer?]
[clear? boolean?]
[other-clears? boolean?]
[type (or/c #f 'flonum 'fixnum 'extflonum)])]{
Represents a local-variable reference; it accesses the value in the
stack slot after the first @racket[pos] slots. If @racket[unbox?] is
@racket[#t], the stack slot contains a box, and a value is extracted
from the box. If @racket[clear?] is @racket[#t], then after the value
is obtained, the stack slot is cleared (to avoid retaining a reference
that can prevent reclamation of the value as garbage). If
@racket[other-clears?] is @racket[#t], then some later reference to
the same stack slot may clear after reading. If @racket[type] is
not @racket[#f], the slot is known to hold a specific type of value.}
@defstruct+[(toplevel expr)
([depth exact-nonnegative-integer?]
[pos exact-nonnegative-integer?]
[const? boolean?]
[ready? boolean?])]{
Represents a reference to a top-level or imported variable via the
@racket[prefix] array. The @racket[depth] field indicates the number
of stack slots to skip to reach the prefix array, and @racket[pos] is
the offset into the array.
When the @racket[toplevel] is an expression, if both @racket[const?]
and @racket[ready?] are @racket[#t], then the variable definitely
will be defined, its value stays constant, and the constant is
effectively the same for every module instantiation. If only
@racket[const?] is @racket[#t], then the value is constant, but it
may vary across instantiations. If only @racket[ready?] is
@racket[#t], then the variable definitely will be defined, but its
value may change. If @racket[const?] and @racket[ready?] are both
@racket[#f], then a check is needed to determine whether the
variable is defined.
When the @racket[toplevel] is the right-hand side for
@racket[def-values], then @racket[const?] is @racket[#f]. If
@racket[ready?] is @racket[#t], the variable is marked as immutable
after it is defined.}
@defstruct+[(topsyntax expr)
([depth exact-nonnegative-integer?]
[pos exact-nonnegative-integer?]
[midpt exact-nonnegative-integer?])]{
Represents a reference to a quoted syntax object via the
@racket[prefix] array. The @racket[depth] field indicates the number
of stack slots to skip to reach the prefix array, and @racket[pos] is
the offset into the array. The @racket[midpt] value is used
internally for lazy calculation of syntax information.}
@defstruct+[(application expr)
([rator (or/c expr? seq? any/c)]
[rands (listof (or/c expr? seq? any/c))])]{
Represents a function call. The @racket[rator] field is the
expression for the function, and @racket[rands] are the argument
expressions. Before any of the expressions are evaluated,
@racket[(length rands)] uninitialized stack slots are created (to be
used as temporary space).}
@defstruct+[(branch expr)
([test (or/c expr? seq? any/c)]
[then (or/c expr? seq? any/c)]
[else (or/c expr? seq? any/c)])]{
Represents an @racket[if] form.
After @racket[test] is evaluated, the stack is restored to its depth
from before evaluating @racket[test].}
@defstruct+[(with-cont-mark expr)
([key (or/c expr? seq? any/c)]
[val (or/c expr? seq? any/c)]
[body (or/c expr? seq? any/c)])]{
Represents a @racket[with-continuation-mark] expression.
After each of @racket[key] and @racket[val] is evaluated, the stack is
restored to its depth from before evaluating @racket[key] or
@racket[val].}
@defstruct+[(beg0 expr) ([seq (listof (or/c expr? seq? any/c))])]{
Represents a @racket[begin0] expression.
After each expression in @racket[seq] is evaluated, the stack is
restored to its depth from before evaluating the expression.
Unlike the @racket[begin0] source form, the first expression in
@racket[seq] is never in tail position, even if it is the only
expression in the list.}
@defstruct+[(varref expr) ([toplevel (or/c toplevel? #t)]
[dummy (or/c toplevel? #f)])]{
Represents a @racket[#%variable-reference] form. The @racket[toplevel]
field is @racket[#t] if the original reference was to a constant local
binding. The @racket[dummy] field
accesses a variable bucket that strongly references its namespace (as
opposed to a normal variable bucket, which only weakly references its
namespace); it can be @racket[#f].}
@defstruct+[(assign expr)
([id toplevel?]
[rhs (or/c expr? seq? any/c)]
[undef-ok? boolean?])]{
Represents a @racket[set!] expression that assigns to a top-level or
module-level variable. (Assignments to local variables are represented
by @racket[install-value] expressions.) If @racket[undef-ok?] is true,
the assignment to @racket[id] succeeds even if @racket[id] was not
previously defined (see also @racket[compile-allow-set!-undefined]).
After @racket[rhs] is evaluated, the stack is restored to its depth
from before evaluating @racket[rhs].}
@defstruct+[(apply-values expr)
([proc (or/c expr? seq? any/c)]
[args-expr (or/c expr? seq? any/c)])]{
Represents @racket[(call-with-values (lambda () args-expr) proc)],
which is handled specially by the run-time system.}
@defstruct+[(with-immed-mark expr)
([key (or/c expr? seq? any/c)]
[def-val (or/c expr? seq? any/c)]
[body (or/c expr? seq? any/c)])]{
Represents a @racket[(call-with-immediate-continuation-mark key
(lambda (_arg) _body) val)] expression that is handled specially by
the run-time system to avoid a closure allocation. One initialized
slot is pushed onto the stack after @racket[expr] and @racket[val]
are evaluated and before @racket[body] is evaluated.
After each of @racket[key] and @racket[val] is evaluated, the stack is
restored to its depth from before evaluating @racket[key] or
@racket[val].}
@defstruct+[(primval expr)
([id exact-nonnegative-integer?])]{
Represents a direct reference to a variable imported from the run-time
kernel.}
@; --------------------------------------------------
@section{Syntax Objects}
@defstruct+[(stx-obj zo)
([datum any/c]
[wrap wrap?]
[srcloc (or/c #f srcloc?)]
[props (hash/c symbol? any/c)]
[tamper-status (or/c 'clean 'armed 'tainted)])]{
Represents a syntax object, where @racket[wrap] contains lexical
information, @racket[srcloc] is the source location,
@racket[props] contains preserved properties,
and @racket[tamper-status] is taint information. When the
@racket[datum] part is itself compound, its pieces are wrapped
as @racket[stx-obj]s, too.
The content of @racket[wrap] is typically cyclic, since it includes
scopes that contain bindings that refer to scopes.}
@defstruct+[(wrap zo) ([shifts (listof module-shift?)]
[simple-scopes (listof scope?)]
[multi-scopes (listof (list/c multi-scope? (or/c #f exact-integer?)))])]{
Lexical information for a syntax object. The @racket[shifts] field
allows binding information to be relative to the enclosing module's
run-time path. The @racket[simple-scopes] field records scopes that
are attached to the syntax object at all phases, and @racket[multi-scopes]
records phase-specific scopes (which are always attached as a group)
along with a phase shift for every scope within the group.}
@defstruct+[(module-shift zo) ([from (or/c #f module-path-index?)]
[to (or/c #f module-path-index?)]
[from-inspector-desc (or/c #f symbol?)]
[to-inspector-desc (or/c #f symbol?)])]{
Records a history of module path index replacements. These replacements
are applied in reverse order, and a module instantiation typically adds
one more shift to replace the current ``self'' module path index
with a run-time module path. The @racket[from] and @racket[to]
fields should be both @racket[#f] or both non-@racket[#f].
The @racket[from-inspector-desc] and @racket[to-inspector-desc] fields
similarly should be both @racket[#f] or both non-@racket[#f]. They
record a history of code-inspector replacements.}
@defstruct+[(scope zo) ([name (or/c 'root exact-nonnegative-integer?)]
[kind symbol?]
[bindings (listof (list/c symbol? (listof scope?) binding?)) #;#:mutable]
[bulk-bindings (listof (list/c (listof scope?) all-from-module?)) #;#:mutable]
[multi-owner (or/c #f multi-scope?) #;#:mutable])]{
Represents a scope. When @racket[name] is @racket['root] then the
scope represents the unique all-phases scope that is shared among
non-module namespaces. Otherwise, @racket[name] is intended to be
distinct for each @racket[scope] instance within a module or top-level
compilation, but the @racket[eq?]-identity of the @racket[scope]
instance ultimately determines its identity. The @racket[kind] symbol
similarly acts as a debugging hint in the same way as for
@racket[syntax-debug-info].
The @racket[bindings] list indicates some bindings that are associated
with the scope. Each element of the list includes a symbolic name, a
list of scopes (including the enclosing one), and the binding for the
combination of name and scope set. A given symbol can appear in
multiple elements of @racket[bindings], but the combination of the
symbol and scope set are unique within @racket[bindings] and across
all scopes. The mapping of a symbol and scope set to a binding is
recorded with an arbitrary member of the scope set.
The @racket[bulk-bindings] field lists bindings of all exports from a
given module, which is an optimization over including each export in
@racket[bindings]. Elements of @racket[bindings] take precedence over
elements of @racket[bulk-bindings], and earlier elements of
@racket[bulk-bindings] take precedence over later elements.
If the @racket[scope] represents a scope at a particular phase for a
group of phase-specific scopes, @racket[mark-owner] refers to the
group.}
@defstruct+[(multi-scope zo) ([name exact-nonnegative-integer?]
[src-name any/c]
[scopes (listof (list/c (or/c #f exact-integer?) scope?)) #;#:mutable])]{
Represents a set of phase-specific scopes that are added or removed
from lexical information as a group. As for @racket[scope], the
@racket[name] field is intended to be distinct for different groups,
but the @racket[eq?] identity of the @racket[multi-scope] record
ultimately determines its identity. The @racket[src-name] field
similarly acts as a debugging hint in the same way as for
@racket[syntax-debug-info].
Scopes within the group are instantiated at different phases on
demand. The @racket[scopes] field lists all of the scopes instantiated
for the group, and the phase at which it is instantiated. Each element
of @racket[scopes] must have a @racketidfont{multi-owner} field
value that refers back to the @racket[multi-scope].}
@defstruct+[(binding zo) ()]{
A supertype for all binding representations.}
@defstruct+[(module-binding binding) ([encoded any/c])]{
Represents a binding to a module or top-level definition. The
@racket[encoded] field can be unpacked using
@racket[decode-module-binding], providing the symbol name for which
the binding is the target (since @racket[encoded] can be relative to
that name).}
@defstruct+[(decoded-module-binding binding) ([path (or/c #f module-path-index?)]
[name symbol?]
[phase exact-integer?]
[nominal-path (or/c #f module-path-index?)]
[nominal-export-name symbol?]
[nominal-phase (or/c #f exact-integer?)]
[import-phase (or/c #f exact-integer?)]
[inspector-desc (or/c #f symbol?)])]{
Represents a binding to a module or top-level definition---like
@racket[module-binding], but in normalized form:
@itemlist[
@item{@racket[path]: the referenced module.}
@item{@racket[name]: the referenced definition within its module.}
@item{@racket[phase]: the phase of the referenced definition within
its module.}
@item{@racket[nominal-path]: the module that was explicitly imported
into the binding context; this path can be different from
@racket[path] when a definition is re-exported.}
@item{@racket[nominal-export-name]: the name of the binding as
exported from @racket[nominal-path], which can be different from
@racket[name] due to renaming on export.}
@item{@racket[nominal-phase]: the phase of the export from
@racket[nominal-path], which can be different from @racket[phase]
due to re-export from a module that imports at a phase level other
than @racket[0].}
@item{@racket[import-phase]: the phase of the import of
@racket[nominal-path], which shifted (if non-@racket[0]) the
binding phase relative to the export phase from
@racket[nominal-path].}
@item{@racket[inspector-desc]: a name for an inspector (mapped to a
specific inspector at run time) that determines access to the
definition.}
]}
@defstruct+[(local-binding binding) ([name symbol?])]{
Represents a local binding (i.e., not at the top level or module level).
Such bindings rarely appear in bytecode, since @racket[quote-syntax]
prunes them.}
@defstruct+[(free-id=?-binding binding) ([base (and/c binding?
(not/c free-id=?-binding?))]
[id stx-obj?]
[phase (or/c #f exact-integer?)])]{
Represents a binding that includes a @racket[free-identifier=?] alias
(to an identifier with a particular phase shift) as well as a base binding.}
@defstruct+[(all-from-module zo) ([path module-path-index?]
[phase (or/c exact-integer? #f)]
[src-phase (or/c exact-integer? #f)]
[inspector-desc symbol?]
[exceptions (listof symbol?)]
[prefix (or/c symbol? #f)])]{
Describes a bulk import as an optimization over individual imports of
a module's exports:
@itemlist[
@item{@racket[path]: the imported module.}
@item{@racket[phase]: the phase of the import module's exports.}
@item{@racket[src-phase]: the phase at which @racket[path] was
imported; @racket[src-phase] combined with @racket[phase]
determines the phase of the bindings.}
@item{@racket[inspector-desc]: a name for an inspector (mapped to a
specific inspector at run time) that determines access to the
definition.}
@item{@racket[exceptions]: exports of @racket[path] that are omitted
from the bulk import.}
@item{@racket[prefix]: a prefix, if any, applied (after
@racket[exceptions]) to each of the imported names.}
]}