text:
Syntax and Macros
MzScheme supports the R5RS
let-syntax, and
letrec-syntax forms with
syntax-rules, with minor pattern and template extensions
described in section 12.1.
In addition to
syntax-rules, MzScheme supports macros that
perform arbitrary transformations on syntax. In particular, a
transformer expression -- the right-hand side of a
let-syntax, or
letrec-syntax binding -- can be an arbitrary expression,
and it is evaluated in a transformer environment. When the
expression produces a procedure, it is associated as a syntax
transformer to the identifier bound by
let-syntax, or
letrec-syntax. This more general,
mostly hygienic macro system is based on
syntax-case by
Dybvig, Hieb, and
Bruggeman (see ``Syntactic abstraction in
Scheme'' in Lisp and Symbolic Computation, December 1993).
A transformer procedure consumes a syntax object and produces a new syntax object. A syntax object encodes S-expression structure, but also includes source-location information and lexical-binding information for each element within the S-expression. A syntax object is a first-class value, and it can exist at run-time. However, syntax objects are more typically used at syntax-expansion time -- which is the run-time of a transformer procedure.45
Unlike traditional
defmacro systems, MzScheme keeps the
top-level transformer environment separate from the normal top-level
environment. The environments are separated because the expressions
in the different environments are evaluated at different times
(transformer expressions are evaluated at syntax-expansion time,
while normal expressions are evaluated at run time). Separating each
environment ensures that compilation and analysis tools can process
programs properly. See section 12.3.3 for more information.
Also unlike traditional macro systems, a transformer procedure is invoked whenever its identifier is used in an expression position, not in application positions only. Even more generally, a transformer expression might not produce a procedure value, in which case the non-procedure is associated to its identifier as a generic expansion-time value. For example, a unit signature (see Chapter 55 in PLT MzLib: Libraries Manual) is associated to an identifier through an expansion-time value. See section 12.6 for more information on transformer applications and expansion-time values.
syntax-rules Extensions
MzScheme extends the pattern language for
syntax-rules so
that a pattern of the form
(... pattern)
is equivalent to
pattern where
... is
treated like any other identifier. Similarly, a template of the form
(... template)
is equivalent to
template where
... is treated like any
other identifier.
In a pattern, additional patterns can follow
..., but only one
... can appear in a sequence:
(pattern ···1 ... pattern ···)
Furthermore, a sequence containing
... can end with a dotted
(pattern ···1 ... pattern ··· . pattern)
but in this case, the final
pattern is never matched to a
syntactic list.
A template element consists of any number of
...s after a
template. For each
... after the first one, the preceding
element (with earlier
...s) is conceptually wrapped with
parentheses for generating output, and then wrapping parentheses in
the output are removed. If a pattern identifier is followed by more
ellipses in a template than in the pattern, then the pattern's match
is expanded normally for inner ellipses (up to the number of ellipses
that appear in the pattern), and then the match is replicated as
necessary to satisfy outer ellipses.
To mesh gracefully with modules, literal identifiers are compared with
, which is equivalent to the comparison
behavior of R5RS in the absence of modules; see section 12.3.1
for more information on identifier syntax comparisons.
define-syntaxex1 (syntax-rules () [(ex1 a) '(a (... ...))])) (ex1 1) ; =>
'(1 ...)(
define-syntaxex2 (syntax-rules () [(ex2 a ... b) '(b a ...)])) (ex2 1 2 3) ; =>
'(3 1 2)(
define-syntaxex3 (syntax-rules () [(ex3 a ... b . c) '(b a ... c)])) (ex3 1 2 3 4) ; syntax error (ex3 1 2 3 . 4) ; =>
'(3 1 2 4)(
define-syntaxex4 (syntax-rules () [(ex4 (a ...) ... b) '(a ... ... b)])) (ex4 (1) (2 3) 4) ; =>
'(1 2 3 4)
syntax-id-rules form has
the same syntax as
syntax-rules, except that each pattern is
used in its entirety (instead of starting with a keyword placeholder
that is ignored). Furthermore, when an identifier
id is bound
as syntax to a
syntax-id-rules transformer, the transformer is
applied whenever
id appears in an expression position -- not
just when it is in the application position -- or when
appears as the target of an assignment. When the identifier appears
in an application position,
(id expr ···), the entire
``application'' is provided to the transformer, and when the
identifier appears as a
set! target,
(set! id
expr), the entire
set! expression is provided to the
transformer; otherwise, the
id is provided alone to the
transformer. Typically,
set! is included as a keyword in a
syntax-id-rules use, and three patterns match the three
possible uses of the identifier.
define-syntaxpwd ; For this macro to work, the
set!case must ; be first, and the
pwdcase must be last (syntax-id-rules (set!) [(set! pwd expr) (
current-directoryexpr)] [(pwd expr ...) ((
current-directory) expr ...)] [pwd (
current-directory)])) (set! pwd "/tmp") ; sets
parameter pwd ; =>
current-directory) ; =>
current-directory"/usr/tmp") pwd ; =>
12.2 Syntax Objects
(read-syntax [
source-name-v input-port]
) is like
except that it produces a syntax object with source-location
information. The
source-name-v is used as the source field of
the syntax object; it can be an arbitrary value, but it should
generally be a path for the source file. The
source-name-v is the input port's name (according
see section 6.2.3). See section 11.2.4 for more information
, see section 184.108.40.206
for information about port locations, and see section 12.6.2 for
information on the
'paren-shape property and
original-indicator property attached to a syntax object
The result of
is a syntax object with
source-location information, but no lexical information. Syntax
objects acquire lexical information during expansion, so that by the
time a transformer is called, the provided syntax object has lexical
, and
procedures work
on syntax objects, especially syntax objects with no lexical
context. (If one of these procedures is given a non-syntax
S-expression, the S-expression is converted to a syntax object
containing no source information and no lexical context.) Each of
these procedures adds context to the syntax object using
namespace-syntax-introduce before expanding the syntax (but
see section 14.1 for information on the special handling of
module). In contrast, the
expand-syntax-once, and
procedures do not add context to a given syntax object before
The syntax object produced by
etc. includes lexical information that influences future expansion
and compilation of the syntax object. Thus, a syntax object produced
should be passed to
(or another procedure without
-syntax in its
name), but a syntax object returned by
should be
passed to
eval-syntax (or another procedure with
-syntax in its name), since the result from
has acquired a lexical context.
For example, if the following text is parsed by
(lambda (x) (+ x y))
the result is a syntax object that contains the S-expression structure
'(lambda (x) (+ x y)), but also source information
indicating that the first
x is in column 9, etc. If
is applied to the syntax object with a normal
top-level environment, then the result will be a similar syntax
object (with the source-location information intact), but the second
x in the syntax object will have lexical information that
ties it to the first
x, and
y in the syntax object
will be annotated as a free variable. Even the syntax object's
'lambda will have lexical information tying it to the
lambda form.
Compilation (often as a prelude to interactive evaluation) strips away
source and context information as it processes a syntax object. The
compilation of a
quote-syntax form is an exception:
(quote-syntax datum)
quote-syntax form produces a syntax object that preserves
the source-location information for
datum. It also encapsulates
lexical-binding information accumulated by compilation in the
quote-syntax expression's environment. A
quote-syntax expression rarely appears in normal expressions;
quote-syntax is more typically used within a transformer
In addition to local and lexical information, a syntax object may have
properties and certificates attached. Properties are added or
inspected using
syntax-property, as described in
section 12.6.2. Certificates validate references to identifiers
that are not exported from a macro, as described in
section 12.6.3.
procedure strips away location,
lexical, property, and certificate information from a syntax object
to produce a plain S-expression. The
procedure wraps syntax information onto an S-expression, copying the
source-location information of a given syntax object, the lexical
information of another syntax object, and the properties of a third
syntax object (where some or all three of the given objects can be
the same). The
procedure unwraps only the immediate
S-expression structure from a syntax object, leaving nested structure
in place. These procedures are described in section 12.2.2.
Although procedures such as
arbitrary manipulation of syntax objects, a syntax transformer is
more likely to use the pattern-matching
syntax-case and
syntax forms, which are described in the following
12.2.1 Syntax Patterns
syntax-case form pattern-matches and deconstructs a
syntax object:
(syntax-case stx-expr (
literal-identifier ...)
syntax-clause is one of
(pattern expr)
(pattern fender-expr expr)
stx-expr expression does not produce a syntax object value,
it is converted to one using
with the
lexical context of the expression (see section 12.2.2). The syntax
is then compared to the
pattern in each
until a match is found, and the result of the corresponding
expr is the result of the
syntax-case expression. If
syntax-clause contains a
fender-expr, the clause
matches only when both the
pattern matches the syntax object
and the
fender-expr returns a true value. If no pattern
matches, a ``bad syntax''
exn:fail:syntax exception is raised.
pattern is nearly the same as a
syntax-rules pattern
(see R5RS), with the ellipsis-escaping extension (see
section 12.1). The difference is that the first identifier in
pattern is not ignored, unlike the leading keyword in a
syntax-rules pattern.
As in
syntax-rules, a non-literal identifier in a
pattern is bound to a corresponding part of the syntax object
within the clause's
expr and optional
fender-expr. The
identifier cannot be used directly, however; a use of the identifier
in an expression position is a syntax error. Instead, the identifier
can be used only in
syntax expressions within the binding's
syntax expression has the form
(syntax template)
template is as in
syntax-rules (extended, as
usual, for escaped ellipses). The result of a
expression is a syntax object. Identifiers in the
template that
are bound by a
syntax-case pattern are replaced with their
bindings in the generated syntax object. A
syntax expression
that contains no pattern identifiers is equivalent to a
quote-syntax expression, except that unlike
quote-syntax, the
syntax form always fails to compile
(i.e., it loops forever) when
template is cyclic.
syntax-rules form can be expressed as a
form wrapped in
(syntax-rules (
literal-identifier···) ((ignored-identifier . pattern) template) ···) =expands=> (lambda (stx) (syntax-case stx (
literal-identifier···) ((generated-identifier . pattern) (syntax template)) ···))
Note that implicit
lambda of
syntax-rules for the
transformer procedure is made explicit with
syntax-case. The
define-syntax form supports
abbreviations for transformer procedures (see section 2.8.1).
The following example shows one reason to use
instead of
syntax-rules: custom error reporting.
define-syntax(let1 stx) (syntax-case stx () [(_ id val body) (begin ;; If
idis not an identifier, report an error in terms of
let1instead of
let: (unless (
identifier?(syntax id)) (
raise-syntax-error#f "expected an identifier" stx (syntax id))) (syntax (let ([id val]) body)))])) (let1 x 10 (
add1x)) ; =>
11(let1 2 10 (
add1x)) ; => let1: expected an identifier at:
(let1 2 10 (
Another reason to use
syntax-case is to implement
``non-hygienic'' macros that introduce capturing identifiers:
define-syntax(if-it stx) (syntax-case stx () [(src-if-it test then
else) (syntax-case (
datum->syntax-object(syntax src-if-it) 'it) () [it (syntax (let ([it test]) (if it then
else)))])]))) (if-it (
memq'b '(a b c)) it 'nope) ; =>
'(b c)
The nested
syntax-case is used to bind the pattern variable
it. The syntax for
it is generated with
using the context of
src-if-it, which means that the introduced variable has
the same lexical context as
if-it at the macro's use; in
other words,
it acts as if it existed in the input syntax,
so it can bind uses of
it in
syntax-case* form is a generalization of
syntax-case where the procedure for comparing
literal-identifiers is determined by a
(syntax-case* stx-expr (
literal-identifier ...) comparison-proc-expr
The result of
comparison-proc-expr must be a procedure that
accepts two arguments. The first argument is an identifier from
stx-expr, and the second argument is an identifier from a
syntax-clause pattern that is
one of the
literal-identifiers. A true result from the
comparison procedure indicates that the first identifier matches the
184.108.40.206 Binding Pattern Variables
with-syntax form is a
let-like form for
binding pattern variables:
(with-syntax ((pattern stx-expr) ···) expr)
patterns are matched the
stx-expr values, and all
pattern identifiers are bound in
expr. The pattern identifiers
across all
patterns must be distinct. If a
expression does not produce a syntax object, its result is converted
and the lexical context of the
stx-expr (see section 12.2.2). If the result of a
stx-expr does not match its
pattern, the
exn:fail:syntax exception is raised.
if-it example can be written more simply using
define-syntax(if-it stx) (syntax-case stx () [(src-if-it test then
else) (with-syntax ([it (
datum->syntax-object(syntax src-if-it) 'it)]) (syntax (let ([it test]) (if it then
Macros that expand to non-hygienic macros rarely work as intended. For example:
define-syntax(cond-it stx) (syntax-case stx () [(_ (test body) .
rest) (syntax (if-it test body (cond-it .
rest)))] [(_) (syntax (
void))])) (cond-it [(
memq'b '(a b c)) it] [#t 'nope]) ; => undefined variable
The problem is that
cond-it introduces
(hygienically), so
cond-it effectively introduces
it (hygienically), which doesn't bind
it in the
source use of
cond-it. In general, the solution is to avoid
macros that expand to uses of non-hygienic macros.46
220.127.116.11 Quasiquoting Templates
quasisyntax form is like
syntax, except with
quasiquoting within the template:
(quasisyntax quasitemplate)
quasitemplate is the same as a
template, except
unsyntax and
unsyntax-splicing escape
to an expression:
(unsyntax expr) (unsyntax-splicing expr)
The expression must produce a syntax object (or syntax list) to be
substituted in place of the
unsyntax or
unsyntax-splicing form within the quasiquoting template,
just like
unquote and
unquote-splicing within
quasiquote. (If the escaped expression does not generate a
syntax object, it is converted to one in the same was as for the
right-hand sides of
with-syntax.) Nested
quasisyntaxes introduce quasiquoting layers in the same way
as nested
Also analogous to
quote and
quasiquote, the reader
#' to
#` to
#, to
unsyntax, and
#,@ to
unsyntax-splicing. See also
section 11.2.4.
(with-syntax ([(v ...) (
list1 2 3)]) #`(0
v... #,(+ 2 2) #,@(
list5 6) 7)) ; => syntax for
(0 1 2 3 4 5 6 7)
126.96.36.199 Assigning Source Location
syntax/loc form is like
syntax, except that
the immediate resulting syntax object takes its source-location
information from a supplied syntax object, unless the
is just a pattern variable:
(syntax/loc location-stx-expr template)
syntax/loc instead of
syntax whenever possible
to help tools that report source locations. For example, the earlier
if-it example should have been written with
define-syntax(if-it stx) (syntax-case stx () [(src-if-it test then
else) (with-syntax ([it (
datum->syntax-object(syntax src-if-it) 'it)]) (syntax/loc stx (let ([it test]) (if it then
quasisyntax/loc form is the quasiquoting analogue of
(quasisyntax/loc location-stx-expr template)
12.2.2 Syntax Object Content
) returns
#t if
v is a syntax object,
#f otherwise.
) returns the source for the syntax object
stx, or
#f if none is known. The source is represented
by an arbitrary value (e.g., one passed to
), but
it is typically a file path string. See also section 14.3.
) returns the line number (positive exact
integer) for the start of the syntax object in its source, or
#f if the line number or source is unknown. The result is
#f if and only if
( produces
syntax-column stx)
#f. See also section 126.96.36.199 and section 14.3.
) returns the column number (non-negative exact
integer) for the start of the syntax object in its source, or
#f if the source column is unknown. The result is
#f if and only if
( produces
syntax-line stx)
#f. See also section 220.127.116.11 and section 14.3.
) returns the character position (positive
exact integer) for the start of the syntax object in its source, or
#f if the source position is unknown. See also
section 126.96.36.199 and section 14.3.
) returns the span (non-negative exact integer)
in characters of the syntax object in its source, or
#f if
the span is unknown. See also section 14.3.
) returns
#t if
stx has the
property that
attach to the syntax objects that they generate (see
section 12.6.2), and if
stx's lexical information does not
indicate that the object was introduced by a syntax transformer (see
section 12.3). The result is
#f otherwise. This
predicate can be used to distinguish syntax objects in an expanded
expression that were directly present in the original expression, as
opposed to syntax objects inserted by macros.
) returns a module path index or symbol
(see section 5.4.2) for the module whose source contains
stx, or
#f if
stx has no source module.
) unwraps the immediate S-expression structure from
a syntax object, leaving nested syntax structure (if any) in place.
The result of
(syntax-e is one of the following:
a symbol
a syntax pair (described below)
the empty list
a vector containing syntax objects
some other kind of datum, usually a number, boolean, or string
A syntax pair is a pair containing a syntax object as its first element, and either the empty list, a syntax pair, or a syntax object as its second element.
A syntax object that is the result of
the use of dots (
.) in the input by creating a syntax object
for every pair of parentheses in the source, and by creating a
pair-valued syntax object only for parentheses in the
source. For example:
) returns an immutable list of syntax objects or
#f. The result is a list of syntax objects when
( would produce a list. In other
words, syntax pairs in
(syntax-e are
) returns an S-expression by
stripping the syntactic information from
stx. Graph
structure is preserved by the conversion.
ctxt-stx v [
src-stx-or-list prop-stx cert-stx]
converts the S-expression
v to a syntax object, using
syntax objects already in
v in the result. Converted
objects in
v are given the lexical context information of
ctxt-stx and the source-location information of
src-stx-or-list. If
v is not already a syntax object, then the
resulting immediate syntax object it is given the properties (see section 12.6.2) of
prop-stx and the inactive certificates
(see section 12.6.3) of
Any of
prop-stx, or
can be
#f, in which case the
resulting syntax has no lexical context, source information, new properties,
and/or certificates.
src-stx-or-list is not
or a syntax object, it must be a list of five elements:
list source-name-v line-k column-k position-k span-k)
source-name-v is an arbitrary value for the source
line-k is a positive, exact integer for the source
line, or
#f; and
column-k is a non-negative,
exact integer for the source column, or
position-k is a positive, exact integer for the source
position, or
#f; and
span-k is a non-negative,
exact integer for the source span, or
#f. The
line-k and
column-k values must both be numbers or
both be
#f, otherwise the
exn:fail exception is raised.
Graph structure is preserved by the conversion of
v to a
syntax object, but graph structure that is distributed among
distinct syntax objects in
v may be hidden from future
applications of
to the new syntax object.
) returns
#t if
stx might be
preservably shared within a syntax object created by
read-honu-syntax, or
. In general, sharing detection is
approximate --
can construct
syntax objects with sharing that is hidden from
-- but
#t for at least one syntax object in a cyclic
structure. Meanwhile, deconstructing a syntax object with
procedures such as
and comparing the results
can also fail to detect sharing (even
cycles), due to the way lexical information is lazily
propagated; only
reliably exposes
sharing in a way that can be detected with
) returns
#t if
v is a syntax
object and
(syntax-e produces a symbol.
) returns a list of identifiers
that are distinct from all other identifiers. The list contains
as many identifiers as
stx-pair contains elements. The
stx-pair argument must be a syntax pair that can be
flattened into a list. The elements of
stx-pair can be
anything, but string, symbol, and identifier elements will be
embedded in the corresponding generated name (useful for
debugging purposes). The generated identifiers are built with
interned symbols (not
gensyms), so the limitations
described in section 14.3 do not apply.
12.3 Syntax and Lexical Scope
Hygienic macro expansion depends on information associated with each
syntax object that records the lexical context of the site where the
syntax object is introduced. This information includes the identifiers
that are bound by
etc., at the syntax object's introduction site, the
identifiers at the introduction site, and the macro expansion that
introduces the object.
Based on this information, a particular identifier syntax object falls into one of three classifications:
lexical -- the identifier is bound by
letrec, or some other form besides
moduleor a top-level definition.
module-imported -- the identifier is bound through a
requiredeclaration or a top-level definition within
free -- the identifier is not bound (and therefore refers to a top-level definition, if the identifier is not within a module).
identifier-binding procedure (described in
section 12.3.2) reports an identifiers classification. Further
information about a lexical identifier is available only in relative
terms, such as whether two identifiers refer to the same binding (see
in section 12.3.1). For module-imported
identifiers, information about the module source is available.
In a freshly read syntax object, identifiers have no lexical information, so they are all classified as free. During expansion, some identifiers acquire lexical or module-import classifications. An identifier that becomes classified as lexical will remain so classified, though its binding might shift as expansion proceeds (i.e., as nested binding expressions are parsed, and as macro introductions are tracked). An identifier classified as module-imported might similarly shift to the lexical classification, but if it remains module-imported, its source-module designation will never change.
Lexical information is used to expand and parse syntax in a way that it obeys lexical and module scopes. In addition, an identifier's lexical information encompasses a second dimension, which distinguishes the environment of normal expressions from the environment of transformer expressions. The module bindings of each environment can be different, so an identifier may be classified differently depending on whether it is ultimately used in a normal expression or in a transformer expression. See section 12.3.3 and section 12.3.4 for more information on the two environments.
12.3.1 Syntax Object Comparisons
a-id-stx b-id-stx
) returns
#t if
the identifier
a-id-stx would bind
b-id-stx (or
vice-versa) if the identifiers were substituted in a suitable
expression context,
#f otherwise.
a-id-stx b-id-stx
) returns
#t if
a-id-stx and
b-id-stx access the same lexical,
module, or top-level binding and return the same result for
#f otherwise.
a-id-stx b-id-stx
) returns
#t if
a-id-stx and
b-id-stx access the same lexical,
module, or top-level binding in the normal environment. ``Same
module binding'' means that the identifiers refer to the same
original definition site, not necessarily the
provide site. Due to renaming in
provide, the identifiers may return distinct
results with
a-id-stx b-id-stx
) returns
#t if
a-id-stx and
b-id-stx access the
same lexical, module, or top-level binding in the identifiers'
transformer environments (see section 12.3.3).
a-id-stx b-id-stx
) returns
#t if
a-id-stx and
b-id-stx access the
same lexical or module binding in the identifiers' template
environments (see section 12.3.4).
) compares each
identifier in
id-stx-list with every other identifier in
the list with
. If any comparison
#t, one of the duplicate identifiers is
returned (the first one in
id-stx-list that is a
duplicate), otherwise the result is
12.3.2 Syntax Object Bindings
) returns one of three kinds of
values, depending on the binding of
id-stx in its normal
The result is
id-stxis bound in its context to anything other than a top-level variable or a module variable.
The result is a list of five items when
id-stxis bound in its context to a module-defined identifier:
listsource-mod source-id nominal-source-mod nominal-source-id et?)
source-modis a module path index or symbol (see section 5.4.2) that indicates the defining module.
source-idis a symbol for the identifier's name at its definition site in the source module. This can be different from the local name returned by
for several reasons: the identifier is renamed on import, it is renamed on export, or it is implicitly renamed because the identifier (or its import) was generated by a macro invocation.
nominal-source-modis a module path index or symbol (see section 5.4.2) that indicates the module
required into the context of
id-stxto provide its binding. It can be different from
source-moddue to a re-export in
nominal-source-modof some imported identifier.
nominal-source-idis a symbol for the identifier's name as exported by
nominal-source-mod. It can be different from
source-iddue to a renaming
provide, even if
nominal-source-modare the same.
#tif the source definition is for-syntax,
The result is
id-stxis not bound (or bound only to a top-level variable) in its lexical context.
) is like
, except that the reported
information is for the identifier's bindings in the transformer
environment (see section 12.3.3), instead of the normal
environment. If the result is
'lexical for either of
, then the result is
'lexical for both.
) is like
, except that the reported
information is for the identifier's bindings in the template
environment (see section 12.3.4), instead of the normal
environment. If the result is
'lexical for either of
identifier-template-binding, then the result is always
'lexical for both.
) returns either
#f or an exact non-negative integer. It returns an
integer only when
identifier-binding returns a list, when
id-stx represents an imported binding, and when the source
module assigns internal positions for its definitions. This
function is intended for use by mzc.
) is
identifier-binding-export-position, except that
the reported information is for the transformer
environment. This function is intended for use by mzc.
12.3.3 Transformer Environments
The top-level environment for transformer expressions is separate from the normal top-level environment. Consequently, top-level definitions are not available for use in top-level transformer definitions. For example, the following program does not work:
(define count 0) (define (inc!) (set! count (
add1count))) (
define-syntax(let1 stx) (syntax-case stx () [(_ x v b) (begin (
printf"expanding ~a~n" count) ; DOESN'T WORK (inc!) ; ALSO DOESN'T WORK (syntax (let ([x v]) b)))])) (let1 x 2 (
The variables
count and
inc! are bound in the normal
top-level environment, but it is not bound in the transformer
environment, so the attempt to expand
(let1 x 2 (
will result in an undefined-variable error.
add1 x))
In the same way that
define binds only in the normal
environment, a
require expression imports only into the
normal environment, and the imported bindings are not made visible in
the transformer environment. A top-level
imports into the transformer environment without affecting the normal
environment. Furthermore, the
require and
require-for-syntax forms create separate instantiations of
any module that is imported into both environments, in keeping with
the separation of the environments.
The initial namespace created by the stand-alone MzScheme application imports all of MzScheme's built-in syntax, procedures, and constants into the transformer environment.47 To extend this environment, use one of the following:
define-for-syntax, which is like
define, but binds in the transformer environment. The body of the definition is also evaluated in the transformer environment. The
define-values-for-syntaxform is the multiple-values variant of
define-for-syntax. Within a module,
define-values-for-syntaxbinds identifiers for unquoted expressions only after the definition (plus in the right-hand side of the definition itself); in particular, mutually-referential for-syntax definitions in a module must be defined with a single
begin-for-syntax, which is like
begin, but its body is evaluated in the transformer environment. Furthermore,
require, and
require-for-templatedeclarations are treated like
require-for-syntax, and
requiredeclarations, respectively.
require-for-syntax, to import bindings into the transformer environment.
In particular, the example above can be repairs by replacing
(define count 0)
(define (inc!) (set! count (
add1 count)))
with either
(define-for-syntax count 0)
(define-for-syntax (inc!) (set! count (
add1 count)))
(define count 0)
(define (inc!) (set! count (
add1 count))))
(module counter
mzscheme(define count 0) (define (inc!) (set! count (
add1count))) (provide count inc!)) (require-for-syntax counter)
When an identifier binding is introduced by a form other than
module or a top-level definition, it extends the environment
for both normal and transformer expressions within its scope, but the
binding is only accessible by expressions resolved in the proper
environment (i.e., the one in which it was introduced). In
particular, a transformer expression in a
let-syntax or
letrec-syntax expression cannot access identifiers bound by
enclosing forms, and an identifier bound in a transformer expression
should not appear as an expression in the result of the
transformer. Such out-of-context uses of an identifier are flagged as
syntax errors when attempting to resolve the identifier.
let-syntax or
letrec-syntax expression can never
usefully appear as a transformer expression, because MzScheme
provides no mechanism for importing into the meta-transformer
environment that would be used by meta-transformer expressions to
operate on transformer expressions. In other words, an expression of
the form
(let-syntax ([identifier (let-syntax ([identifier expr]) body-expr)]) ...)
is always illegal, assuming that
let-syntax is bound in both the
normal and transformer environments to the
let-syntax of
. No syntax (not even function application) is bound in
expr's environment. This restriction in the
language is of little consequence, however, since for-syntax exports
allow the definition of syntax applicable to the above
12.3.4 Module Environments
In the same way that the normal and transformer environments are kept separate at the top level, a module's normal and transformer environments are also separated. Normal imports and definitions in a module -- both variable and syntax -- contribute to the module's normal environment, only.
For example, the module expression
(module m
mzscheme(define (id x) x) (
define-syntax(macro stx) (id (syntax (
is ill-formed because
id is not bound in the transformer
environment for the
macro implementation. To make
id usable from the transformer, the body of the module
would have to be executed -- which is impossible in general, because
a syntax definition such as
macro affects the expansion of the
rest of the module body.
Consequently, if a procedure such as
id is to be used in a
transformer, it must either remain local to the transformer
expression, or reside in a different module. For example, the above
module is trivially repaired as
(module m
define-syntaxmacro (let ([id (lambda (x) x)]) (lambda (stx) (id (syntax (
begin-for-syntax, and
define-syntaxes forms (see section 12.3.3 and
section 12.4) are useful for defining multiple macros that share
helper functions.
In the
language, the base environment for a
transformer expression includes all of MzScheme. The
language also provides a
require-for-syntax form (in the normal environment) for
importing bindings from another module into the importing module's
transformer environment:
(require-for-syntax require-spec ···)
A for-syntax import of M within N causes M to be executed at N's expansion time, instead of (or possibly in addition to) run time for N. The syntax and variable identifiers exported by the for-syntax module are visible within the module's transformer environment, but not its normal environment. Like a normal expression, a transformer expression in a module cannot contain free variables.
require-for-template form is roughly dual to
(require-for-template require-spec ···)
A for-template import of M within N causes the referenced module
to be executed at the run-time of any P that includes a for-syntax
import of N. In other words,
introduces bindings that become available in a future run time.
Finally, the
require-for-label form is similar to
the other
require forms:
(require-for-label require-spec ···)
A for-label import of M introduces bindings that are accessible only
identifier-label-binding etc.
Transformer expressions and imports for a module M are executed once each time a module is expanded using M's syntax bindings or using M as a for-syntax import. After the module is expanded, its transformer environment is destroyed, including bindings from modules used at expansion time.
(module rt
printf"RT here~n") (define mx (lambda () 7)) (provide mx)) (module tt
printf"RT here, too~n") (define x 700) (provide x)) (module et
mzscheme(require-for-template tt) (
printf"ET here~n") ;; The
xbelow is future-time: (define mx (lambda () (syntax x))) (provide mx)) (module m
mzscheme) (require rt) ; rt provides run-time mx (require-for-syntax et) ; et provides exp-time mx ;; The
mxbelow is run-time: (
printf"~a~n" (mx)) ; prints
7when run ;; The
mxbelow is exp-time: (
define-syntaxonem (lambda (stx) (mx))) (
printf"~a~n" (onem)) ; prints
700when run ;; The
mxbelow is run-time: (
define-syntaxtwom (lambda (stx) (syntax (mx)))) (
printf"~a~n" (twom))) ; prints
7when run ;;
"ET here"is printed during the expansion of
m(require m) ; prints
"ET here"(for later macro expansion in the top level, if any) ; and
"RT here, too"and
"RT here"in some order, ; then
7, then
700, then
This expansion-time execution model explains the need to execute
declared modules only when they are invoked. If a declared module is
imported into other modules only for syntax, then the module is
needed only at expansion time and can be ignored at run time. The
separation of declaration and execution also allows a for-syntax
module to be executed once for each module that it expands through
The hierarchy of run times avoids confusion among expansion and executing layers that can prevent separate compilation. By ensuring that the layers are separate, a compiler or programming environment can expand, partially expand, or re-expand a module without affecting the module's run-time behavior, whether the module is currently executing or not.
Since transformer expressions may themselves use macros defined by modules with for-syntax imports (to implement the macros), expansion of a module creates a hierarchy of run times (or "tower of expanders"). The expansion time of each layer corresponds to the run time of the next deeper layer.
In the absence of
let-syntax and
letrec-syntax, the
hierarchy of run times would be limited to three levels, since the
transformer expressions for run-time imports would have been expanded
before the importing module must be expanded. The
let-syntax and
letrec-syntax forms, however, allow syntax visible in a
for-syntax import's transformers to appear in the expansion of
transformer expressions in the module. Consequently, the hierarchy is
bounded in principle only by the number of declared modules. In
practice, the hierarchy will rarely exceed a few levels.
12.3.5 Macro-Generated Top-Level and Module Definitions
When a top-level definition binds an identifier that originates from a macro expansion, the definition captures only uses of the identifier that are generated by the same expansion. This behavior is consistent with internal definitions (see section 2.8.5), where the defined identifier turns into a fresh lexical binding.
define-syntaxdef-and-use-of-x (syntax-rules () [(def-and-use-of-x val) ;
xbelow originates from this macro: (begin (define x val) x)])) (define x 1) x ; =>
1(def-and-use-of-x 2) ; =>
2x ; =>
define-syntaxdef-and-use (syntax-rules () [(def-and-use x val) ;
xbelow was provided by the macro use: (begin (define x val) x)])) (def-and-use x 3) ; =>
3x ; =>
For a top-level definition (outside of
module), the order of
evaluation affects the binding of a generated definition for a
generated identifier use. If the use precedes the definition, then
the use refers to a non-generated binding, just as if the generated
definition were not present. (No such dependency on order occurs
within a
module, since a module binding covers the entire
module body.) To support the declaration of an identifier before its
use, the
define-syntaxes form avoids binding an identifier
if the body of the
define-syntaxes declaration produces zero
results (see also section 12.4).
(define bucket-1 0) (define bucket-2 0) (
define-syntaxdef-and-set!-use-of-x (syntax-rules () [(def-and-set!-use-of-x val) (begin (set! bucket-1 x) (define x val) (set! bucket-2 x))])) (define x 1) (def-and-set!-use-of-x 2) x ; =>
1bucket-1 ; =>
1bucket-2 ; =>
define-syntaxdefs-and-uses/fail (syntax-rules () [(def-and-use) (begin ; Initial reference to
evenprecedes definition: (define (odd x) (if (
zero?x) #f (even (
sub1x)))) (define (even x) (if (
zero?x) #t (odd (
sub1x)))) (odd 17))])) (defs-and-uses/fail) ; => error: undefined identifier
define-syntaxdefs-and-uses (syntax-rules () [(def-and-use) (begin ; Declare before definition via no-values
define-syntaxes: (define-syntaxes (odd even) (
values)) (define (odd x) (if (
zero?x) #f (even (
sub1x)))) (define (even x) (if (
zero?x) #t (odd (
sub1x)))) (odd 17))])) (defs-and-uses) ; =>
Within a module, macro-generated
require and
clauses also introduce and reference generation-specific bindings:
require(see section 5.2), for a
require-specof the form
(, the
local-identifieris bound only for uses of the identifier generated by the same macro expansion as
local-identifier. In
requirefor other
require-specs, the generator of the
require-specdetermines the scope of the bindings.
provide(see section 5.2), for a
provide-specof the form
identifier, the exported identifier is the one that binds
identifierwithin the module in a generator-specific way, but the external name is the plain
identifier. The exceptions for
all-defined-exceptare similarly determined in a generator-specific way, as is the
local-identifierbinding of a
renameform, but plain identifiers are used for the external names. For
struct, the context of the
struct-identifierdetermines local bindings for all of the expanded
structnames. For
all-defined-except, only identifiers with definitions having the same generator as the
all-defined-exceptkeyword are exported; the external name is the plain identifier from the definition. The generator of an
provide-specdoes not affect the set identifiers exported by the
12.4 Binding Multiple Syntax Identifiers
In addition to
let-syntax, and
letrec-syntax, MzScheme provides
let-syntaxes, and
letrec-syntaxes. These forms are analogous to
let-values, and
letrec-values, allowing multiple syntax bindings at once
(see section 2.8).
(define-syntaxes (identifier ···) expr) (let-syntaxes (((identifier ···) expr) ···) expr ···1) (letrec-syntaxes (((identifier ···) expr) ···) expr ···1)
At the top level,
define-syntaxes accepts zero results for
any number of
identifiers, and in that case, it neither binds
the identifiers nor signals an error. This behavior is useful for
identifiers that are introduced by a macro that produces
defines. See section 12.3.5 for more information.
MzScheme also provides a
letrec-syntaxes+values form for
binding both values and syntax in a single, mutually recursive scope:
(letrec-syntaxes+values (((identifier ···) expr) ···) (((identifier ···) expr) ···) expr ···1)
The first set of bindings are syntax bindings (as in
letrec-syntaxes), and the second set of bindings are normal
variable bindings (as in
;; Defines
let-current-continuationas the same macro: (define-syntaxes (
let/cclet-current-continuation) (let ([macro (syntax-rules () [(_ id body1 body ...) (
call/cc(lambda (id) body1 body ...))])]) (
valuesmacro macro))) (letrec-syntaxes+values ([(get-id) (syntax-rules () [(_) id])]) ([(id) (lambda (x) x)] [(x) (get-id)]) x) ; => the
ididentify procedure
12.5 Special Syntax Identifiers
To enable the definition of syntax transformers for application forms
and other data (numbers, vectors, etc.), the syntax expander treats
#%top, and
as special identifiers.
Any expandable expression of the form
(datum . datum)
where the first
datum is not an identifier bound to an
expansion-time value, is treated as
(#%app datum . datum)
so that the syntax transformer bound to
#%app is applied.
In addition,
() is treated as
Similarly, an expression
identifier has no binding other than a top-level binding,
is treated as
(#%top . identifier)
Finally, an expression
datum is not an identifier or pair,
is treated as
(#%datum . datum)
module provides
#%datum as regular application, top-level variable
reference, and implicit quote, respectively. A module can export
different transformers with these names to support languages
different from conventional Scheme.
In the case of
or the default load
handler, every input
datum is wrapped with
(#%top-interaction . datum)
module provides
#%top-interaction as
a macro that expands to just the
#%module-begin is used as a transformer for
the module body. A
#%module-begin is implicitly added
around a module body when it contains multiple S-expressions, or when
the S-expression expands to a core form other
#%module-begin or
#%plain-module-begin; the
lexical context for the introduced
#%module-begin identifier
includes only the exports of the module's initial import. After such
wrapping, if any, and before any expansion,
'enclosing-module-name property is attached to the
module-body syntax object; the property's value is a symbol for the
module name as specified after the
module keyword.
module binds
#%module-begin to a form
that inserts a for-syntax import of
, so
bindings can be used in syntax definitions. It
also exports
#%plain-module-begin, which can be substituted
#%module-begin to avoid the for-syntax import
. Any other transformer used
#%module-begin must expand
When an expression is fully expanded, all applications, top-level
variable references, and literal datum expressions will appear as
#%top, and
#%datum forms,
respectively. Those forms can also be used directly by source
code. The
#%module-begin form can never usefully appear in an
expression, and the body of a fully expanded
module declaration
is not wrapped with
#%module-begin; instead, it is wrapped with
The following example shows how the special syntax identifiers can be defined to create a non-Scheme module language:
(module lambda-calculus
mzscheme; Restrict lambda to one argument: (define-syntax lc-lambda (syntax-rules () [(_ (x) E) (lambda (x) E)])) ; Restrict application to two expressions: (define-syntax lc-app (syntax-rules () [(_ E1 E2) (E1 E2)])) ; Restrict a lambda calculus module to one body expression: (define-syntax lc-module-begin (syntax-rules () [(_ E) (#%module-begin E)])) ; Disallow numbers, vectors, etc. (define-syntax lc-datum (syntax-rules ())) ; Provide (with renaming): (provide #%top ; keep mzscheme's free-variable error (rename lc-lambda lambda) (rename lc-app #%app) (rename lc-module-begin #%module-begin) (rename lc-datum #%datum))) (module m lambda-calculus ; The only syntax defined by
lambda-calculusis ; unary
lambda, unary application, and variables. ; Also, the module must contain exactly one expression. ((lambda (y) (y y)) (lambda (y) (y y)))) (require m) ; executes m, loops forever
12.6 Macro Expansion
let-syntax, or
letrec-syntax form associates an identifier to an
expansion-time value. If the expansion-time value is a procedure of
one argument, then the procedure is applied by the syntax expander
when the identifier is used in the scope of the syntax binding.
The transformer for an
identifier is applied whenever the
identifier appears in an expression position -- not just when
it appears after a parenthesis as
When it does appear as
identifier ...)
(, the entire
identifier ...)
( expression is provided as the
argument to the transformer. Otherwise only
identifier ...)
identifier is
provided to the transformer.
A typical transformer is implemented as
(lambda (stx) (syntax-case stx () [(_ rest-of-pattern) expr]))
so that
identifier by itself does not match the pattern; thus,
exn:fail:syntax exception is raised when
identifier does not appear as
identifier ...)
) also
creates a transformer procedure. The
proc argument must be a
procedure of one argument; if the result of
( is bound as syntax to
make-set!-transformer proc)
identifier, then
proc is applied as a transformer when
identifier is used in an expression position, or when it is
used as the target of a
set! assignment:
(set! . When the identifier
appears as a
set! target, the entire
expression is provided to the transformer.
(let ([x 1] [y 2]) (let-syntax ([x (
make-set!-transformer(lambda (stx) (syntax-case stx (set!) ; Redirect mutation of x to y [(set! id v) (syntax (set! y v))])))] ; Normal use of
xreally gets
x[id (
identifier?(syntax id)) (syntax x)])))]) (begin (set! x 3) (
listx y)))) ; =>
'(1 3)
) returns
#t if
v is a
value created by
) returns the procedure
passed to
make-set!-transformer to create
) creates
a transformer procedure that inserts the identifier
id-stx in
place of whatever identifier binds the transformer, including in
non-application positions, and in
set! expressions. Such a
transformer could be written manually, but the one created by
make-rename-transformer cooperates specially with
syntax-local-value (see below).
) returns
#t if
v is a value
created by
#f otherwise.
) returns the identifier
passed to
make-rename-transformer to create
If a transformer expression produces a non-procedure value, the value
is associated with the identifier as a generic expansion-time
value. Any use of the identifier in an expression position is
rejected as a syntax error, but syntax transformers can access the
value. For example, the
define-signature form (see
Chapter 55
in PLT MzLib: Libraries Manual) associates a component interface
description to the defined identifier.
When a syntax transformer is applied, it can query the bindings of
identifiers in the lexical environment of the expression being
transformed. For example, the
unit form can access a
named interface description with
)returns the expansion-time value of
id-stxin the transformed expression's context. If
id-stxis not bound to an expansion-time value (via
let-syntax, etc.) in the environment of the expression being transformed, the result is obtained by applying
failure-thunk. If
failure-thunkis not provided, the
exn:fail:contractexception is raised. If
id-stxis bound to a rename transformer created with
syntax-local-valueeffectively calls itself with the target of the rename and returns that result, instead of the rename transformer.
id-stxcan use certificates for the expression being transformed (see section 12.6.3) as well as inactive certificates associated with
id-stx(see section 184.108.40.206). Furthermore, if the transformer is defined within a module (i.e., the current transformation was triggered by a use of a module-defined identifier) or if the current expression is being expanded for the body of a module, then resolving
id-stxcan access any identifier defined by the module.
)returns a fresh identifier, and it cooperates with the
begin-for-syntax, and top-level expanders to bind the generated identifier to the expression
stx. A run-time expression within a module is lifted to the module's top level, just before the expression whose expansion requests the lift. Similarly, a run-time expression outside of a module is lifted to a top-level definition. A compile-time expression in a
define-syntaxesbinding is lifted to a
letwrapper around the corresponding right-hand side of the binding. A compile-time expression within
begin-for-syntaxis lifted to a
define-for-syntaxdeclaration just before the requesting expression. Other syntactic forms can capture lifts by using
)returns a value that uniquely indicates a context into which
syntax-local-lift-expressionlifts expressions. The result is
#twhen lifted expressions are placed into the top-level environment.
)cooperates with the
moduleform to insert
stxas a top-level declaration at the end of the module currently being expanded. The result is void. If the current expression being transformed is not within a
moduleform, or if it is not a run-time expression, then the
exn:fail:contractexception is raised. If the current expression being transformed is not in the module top-level, then
stxis eventually expanded in an expression context.
)returns an inferred name for the expression position being transformed, or
#f; see also section 6.2.3.
)returns either
'module-begin, or a non-empty list of arbitrary values.
The first three possibilities indicate that the expression is being expanded for a (non-definition) expression position, a top-level position, or a module top-level position, respectively. The next-to-last,
'module-begin, indicates that the expression is being expanded as the sole form within a module, where it might produce
The last possibility, a list, indicates expansion for an internal-definition position. The identity of the lists's first element (i.e., its
ness) reflects the identity of the internal-definition context; in particular two transformer expansions receive the same first value if and only if they are invoked for the same internal-definition context. Later values in the list similarly identify internal-definition contexts that are still being expanded, and that required the expansion of nested internal-definition contexts.
identifierif no binding in the current expansion context shadows
identifier, if
identifierhas no module context, and if the current expansion context is not a module. If a binding of
identifier, the result is the same as
(syntax-local-get-shadower, except that it has the location and properties of
identifier. Otherwise, the result is the same as
identifierwith its module context (if any) removed and the current module context (if any) added. Thus, the result is an identifier corresponding to the innermost shadowing of
identifierin the current context if its shadowed, and a module-contextless version of
)returns a procedure that captures any certificates currently available for
local-expand. The procedure accepts one to three arguments:
key-v(optional), and
intro-proc(optional). The procedure's result is a syntax object like
stx, except that it includes the captured certificates as inactive (see section 184.108.40.206) if
#f(the default) or active otherwise. If
key-vis supplied and not
#f, it is associated with each captured certificate for later use through
syntax-recertify(see section 18.104.22.168). If
intro-procis supplied, and if it is not
#f(the default), then it must be a procedure created by
make-syntax-introducer, in which case the certificate applies only to parts of
stxthat are marked as introduced by
active?when the syntax to be certified can be safely used in any context by any party, and where access to the syntax object should not confer any additional access. Supply
active?when the syntax to be certified is not accessible to parties that might abuse the access that the certificate provides, and when the certified syntax eventually appears (via macro expansion) within a larger expression from which it cannot be safely extracted by other parties.
#tif an expression is currently being transformed (so that procedures like
syntax-local-valuecan be called),
A transformer can also expand or partially expand subexpressions from its input syntax object:
stx context-v stop-id-stx-list[
stxin the lexical context of the expression currently being expanded. The
context-vargument is used as the result of
syntax-local-contextfor immediate expansions; for a particular internal-definition context, generate a unique value and
consit onto the current result of
syntax-local-contextif it is a list.
When an identifier in
stop-id-stx-listis encountered by the expander in a subexpression, expansions stops for the subexpression. If
#%top, or
#%datum(see section 12.5) appears in
stop-id-stx-list, then application, top-level variable reference, and literal data expressions without the respective explicit form are not wrapped with the explicit form. If
#finstead of a list, then
stxis expanded only as long as the outermost form of
stxis a macro (i.e., expansion does not proceed to sub-expressions).
The optional
intdef-ctxargument must be either
#f(the default) or the result of
syntax-local-make-definition-context. In the latter case, lexical information for internal definitions is added to
stxbefore it is expanded. The lexical information is also added to the expansion result (because the expansion might introduce bindings or references to internal-definition bindings).
Expansion of
stxcan use certificates for the expression already being expanded (see section 12.6.3) , and inactive certificates associated with
stxare activated for
stx(see section 18.104.22.168). Furthermore, if the macro expander is defined within a module (i.e., the current expansion was triggered by a use of a module-defined identifier) or if the current expression is being expanded for the body of a module, then the expansion of
stxcan use any identifier defined by the module.
'expressionand an empty stop list, but with two results: a syntax object for the fully expanded expression, and a syntax object whose content is opaque. The latter can be used in place of the former (perhaps in a larger expression produced by a macro transformer), and when the macro expander encouters the opaque object, it substitutes the fully expanded expression without re-expanding it; the
exn:fail:syntaxexception is raised if the expansion context includes bindings or marks that were not present for the original expansion, in which case re-expansion might produce different results. Consistent use of
syntax-local-expand-expressionand the opaque object thus avoids quadratic expansiontimes when local expansions are nested.
stx context-v stop-id-stx-list intdef-ctx
)is like
local-expand, but
stxis expanded as a transformer expression instead of a run-time expression.
stx context-v stop-id-stx-list intdef-ctx lift-ctx-v
)is like
local-expand, but if
syntax-local-lift-expressionis called during the expansion of
stx, the result is a syntax object that represents a
beginexpression; lifted expression appear with their identifiers in
define-valuesforms, and the expansion of
stxis the last expression in the
begin. The lifted expressions are not expanded. The
lift-ctx-vargument is used as the result of
syntax-local-lift-expressionlifts to the resulting
beginform; supply a unique value that identifies the context into which all lifted definitions are eventually combined.
stx context-v stop-id-stx-list intdef-ctx lift-ctx-v
)is like
local-expand/capture-lifts, but
stxis expanded as a transformer expression instead of a run-time expression. Lifted expressions are reported as
define-valuesforms (in the transformer environment).
)creates an opaque internal-definition context value to be used with
local-expandand other functions. A transformer should create one context for each set of internal definitions to be expanded, and use it when expanding any form whose lexical context should include the definitions. After discovering an internal
define-syntaxesform, use
syntax-local-bind-syntaxesto add bindings to the context.
id-list expr-or-false intdef-ctx
)binds each identifier in
id-listwithin the internal-definition context represented by
intdef-ctx, where
intdef-ctxis the result of
syntax-local-make-definition-context. Supply
expr-or-falsewhen the identifiers correspond to
define-valuesbindings, and supply a compile-time expression when the identifiers correspond to
define-syntaxesbindings; the later case, the number of values produces by the expression should match the number of identifiers, otherwise the
exn:fail:contract:arityexception is raised.
To track the introduction of identifiers by a macro
(see section 12.3), the syntax expander adds a special ``mark''
to a syntax object that is provided to a transformer, and also marks
the result of the transformer. Consecutive marks cancel, and each
transformer application has a distinct mark, so the only parts of the
resulting syntax object with marks are the parts that were introduced
by the transformer. A transformer can explicitly add a current mark
to a syntax object using
syntax-local-introduce or the
result of
)produces a syntax object that is like
stx, except that a mark for the current expansion is added (possibly canceling an existing mark in parts of
)produces a procedure that behaves like
syntax-local-introduce, except using a fresh mark. Multiple applications of the same
make-syntax-introducerresult procedure use the same mark, and different result procedures use distinct marks.
Explicit marking is useful on syntax objects that flow into or out of
a transformer without being the transformer argument or result. For
example, DrScheme's Check Syntax tool recognizes
'disappeared-binding and
properties, which specify bound-binding identifier pairs in the
source program that do not appear in the expansion. Example:
define-syntax(match-list stx) (syntax-case stx () [(_ expr (id ...) result-id) (let ([ids (
syntax->list(syntax (id ...)))] [result-id (syntax result-id)]) ;; Make sure the expression is well formed: (
for-each(lambda (id) (unless (
identifier?id) (
raise-syntax-error#f "not an identifier" stx id))) (
appendids (
listresult-id))) ;; Find the matching identifier and produce a
expression: (let loop ([ids ids] [pos 0]) (cond [(
null?ids) (
raise-syntax-error#f "no pattern binding" stx result-id)] [(
carids) result-id) ;; Found it; produce the
expression, and ;; tell the Check Syntax tool about the pattern-variable binding: (with-syntax ([pos pos]) (
syntax-property(syntax (
list-refexpr pos)) ; the expansion result 'disappeared-binding (
carids))) 'disappeared-use (
syntax-local-introduceresult-id)))] [else (loop (
cdrids) (
add1pos))])))])) ;; Test it: (match-list '(1 2 3) (a b c) b) ; =>
In this example, Check Syntax will draw a binding arrow from the first
b to the second
b. Without the calls to
syntax-local-introduce, the identifiers stored in the
property would appear to have originated from the transformer,
instead of from the transformer's argument; consequently, Check
Syntax would not draw the arrow, because it would not know that the
bs exist in the source program.
12.6.1 Expanding Expressions to Primitive Syntax
) expands all non-primitive syntax in
stx-or-sexpr, and returns a syntax object for the expanded
expression. See below for the grammar of fully expanded
expressions. Before
stx-or-sexpr is expanded, its lexical
context is enriched with
namespace-syntax-introduce as for
(see section 8.3 and
section 14.1). Use
to convert the
returned syntax object into an S-expression.
) is like
(expand , except
that the argument must be a syntax object, and its lexical context is
not enriched before expansion.
) partially expands syntax in the
stx-or-sexpr and returns a syntax object for the
partially-expanded expression. Due to limitations in the expansion
mechanism, some context information may be lost. In particular,
on the result may produce a result that
is different from expansion via
. Before
stx-or-sexpr is expanded, its lexical context is enriched with
namespace-syntax-introduce as for
section 8.3 and section 14.1).
) is like
, except that the argument must be a syntax object, and
its lexical context is not enriched before expansion.
) partially expands syntax in
stx-or-sexpr to reveal the outermost syntactic form. This
partial expansion is mainly useful for detecting top-level uses of
begin. Unlike expanding the result of
expanding the result of
produces the same result as using
the original syntax. Before
stx-or-sexpr is expanded, its
lexical context is enriched with
as for
(see section 8.3 and
section 14.1).
) is like
(expand-to-top-form , except that the argument
must be a syntax object, and its lexical context is not enriched
before expansion.
The possible shapes of a fully expanded expression are defined by
top-level-expr is one of
(#%expression expr)
(module identifier name (#%plain-module-begin module-level-expr ···))
(begin top-level-expr ···)
module-level-expr is one of
(provide provide-spec ...)
general-top-level-expr is one of
(define-values (variable ···) expr)
(define-syntaxes (identifier ···) expr)
(define-values-for-syntax (variable ···) expr)
(require require-spec ···)
(require-for-syntax require-spec ···)
(require-for-template require-spec ···)
expr is one of
(lambda formals expr ···1)
(case-lambda (formals expr ···1) ···)
(if expr expr)
(if expr expr expr)
(begin expr ···1)
(begin0 expr expr ···)
(let-values (((variable ···) expr) ···) expr ···1)
(letrec-values (((variable ···) expr) ···) expr ···1)
(set! variable expr)
quote datum)
(quote-syntax datum)
(with-continuation-mark expr expr expr)
(#%app expr ···1)
(#%datum . datum)
(#%top . variable)
(#%variable-reference variable)
(#%variable-reference (#%top . variable))
formals is defined in section 2.9, and
require-spec and
provide-spec are defined in
section 5.2.
When a
variable expression appears in a fully-expanded
expression, it either refers to a variable bound by
letrec-values, or
define (within the current module), or it refers to an
imported variable. (In other words, a
variable not wrapped by
#%top never refers to a top-level variable.)
The keywords in the above grammar are placeholders for identifiers
that are
expressions) to the same-named exports of
. Due to
import renamings, the printed identifier names can be different in
the expanded expression.
12.6.2 Syntax Object Properties
Every syntax object has an associated property list, which can be
queried or extended with
stx key-v v
stxby associating an arbitrary property value
vwith the key
key-v; the result is a new syntax object with the association (while
stxitself is unchanged).
stx key-v
)returns an arbitrary property value associated to
stxwith the key
key-v, or
#fif no value is associated to
)returns a list of all symbols that as keys have associated properties in
stx. Uninterned symbols (see section 3.7) are not included in the result list.
read-syntax procedure attaches a
property to any pair or vector syntax object generated from parsing a
pair of square brackets (``['' and ``]'') or curly braces (``{'' and
``}'').48 The property value is
#\[ in the former case,
#\{ in the latter case. The
syntax form
copies any
'paren-shape property from the source of a template
to corresponding generated syntax.
Both the syntax input to a transformer and the syntax result of a
transformer may have associated properties. The two sets of
properties are merged by the syntax expander: each property in the
original and not present in the result is copied to the result, and
the values of properties present in both are combined with
(result value first, original value second).
Before performing the merge, however, the syntax expander
automatically add a property to the original syntax object using
the key
'origin. If the source syntax has no
'origin property, it is set to the empty list. Then, still
before the merge, the identifier that triggered the macro expansion
(as syntax) is
d onto the
property so far.
'origin property thus records (in reverse order) the
sequence of macro expansions that produced an expanded
expression. Usually, the
'origin value is an immutable list
of identifiers. However, a transformer might return syntax that has
already been expanded, in which case an
'origin list can
contain other lists after a merge.
For example, the expression
(or x y)
expands to
(let ((or-part x)) (if or-part or-part (or y)))
which, in turn, expands to
(let-values ([(or-part) x]) (if or-part or-part y))
The syntax object for the final expression will have an
'origin property whose value is
(quote-syntax let) (quote-syntax or))
new-stx orig-stx id-stx
) adds properties to
new-stx in the same way that macro expansion adds properties to
a transformer result. In particular, it merges the properties of
orig-stx into
new-stx, first adding
id-stx as an
'origin property, and it returns the property-extended syntax
object. Use the
syntax-track-origin procedure in a macro
transformer that discards syntax (corresponding to
with a keyword
id-stx) leaving some other syntax in its place
(corresponding to
'origin tracking for general macro expansion, MzScheme
adds properties to expanded syntax (often using
syntax-track-origin) to record additional expansion details:
When a
beginform is spliced into a sequence with internal definitions (see section 2.8.5),
syntax-track-originis applied to every spliced element from the
beginbody. The second argument to
syntax-track-originis the
beginform, and the third argument is the
beginkeyword (extracted from the spliced form).
When an internal
define-syntaxesform is converted into a
letrec-values+syntaxesform (see section 2.8.5),
syntax-track-originis applied to each generated binding clause. The second argument to
syntax-track-originis the converted form, and the third argument is the
define-syntaxeskeyword form the converted form.
When a
letrec-values+syntaxesexpression is fully expanded, syntax bindings disappear, and the result is either a
letrec-valuesform (if the unexpanded form contained non-syntax bindings), or only the body of the
letrec-values+syntaxesform (wrapped with
beginif the body contained multiple expressions). To record the disappeared syntax bindings, a property is added to the expansion result: an immutable list of identifiers from the disappeared bindings, as a
When a subtyping
define-structform is expanded, the identifier used to reference the base type does not appear in the expansion. Therefore, the
define-structtransformer adds the identifier to the expansion result as a
When a reference to an unexported or protected identifier from a module is discovered (and the reference is certified; see section 12.6.3), the
'protectedproperty is added to the identifier with a
When or
read-honu-syntaxgenerates a syntax object, it attaches a property to the object (using a private key) to mark the object as originating from a read. The
predicate looks for the property to recognize such syntax objects. (See section 12.2.2 for more information.)
syntax-original? procedure and the
'disappeared-binding, and
'disappeared-use properties
are used by program-processing tools (such as Check Syntax in
DrScheme) to relate source code to its expanded form. Implementors of
macro transformers should consider whether properties added
automatically by MzScheme are sufficient for tools to make sense of
expansion result, and implementors should use
syntax-track-origin and
syntax-property as
necessary to fill in gaps (see section 12.6 for an example).
See section 12.6.5 for information about properties generated by the expansion of a module declaration. See section 3.12.1 and section 6.2.3 for information about properties recognized when compiling a procedure. See section 14.3 for information on properties and byte codes.
12.6.3 Certificates for Protected References
As illustrated in section 5.3, a macro can expand into a use of
an identifier that is not exported from the macro's module. In
general, such an identifier must not be extracted from the expanded
expression and used in a different context, because using the
identifier in a different context may break invariants of the macro's
module. For example, the following module exports a macro
that expands to a use of
(module m
mzscheme(provide go) (define (unchecked-go n x) ;; to avoid disaster,
nmust be a number (+ n 17)) (
define-syntax(go stx) (syntax-case stx () [(_ x) #'(unchecked-go 8 x)])))
If the reference to
unchecked-go is extracted from the
expansion of
(go 'a), then it might be inserted into a
new expression,
(unchecked-go #f 'a), leading to
disaster. The
procedure can be used
similarly to construct references to an unexported identifier, even
when no macro expansion includes a reference to the identifier.
To prevent such abuses of unexported identifiers, MzScheme's macro
expander and compiler reject references to unexported identifiers
unless they appear in certified syntax objects. The macro
expander always certifies a syntax object that is produced by a
transformer. For example, when
(go 'a) is expanded to
(unchecked-go 8 'a), a certificate is attached to the
(unchecked-go 8 'a). Extracting just
unchecked-go removes the identifier from the certified
expression, so that the reference is disallowed when it is inserted
(unchecked-go #f 'a).
In addition to checking module references, the macro expander
disallows references to local bindings where the binding identifier
is less certified than the reference. Otherwise, the expansion
(go 'a) could be wrapped with a local binding that
#%app to
, thus obtaining the value
unchecked-go. Note that a capturing
#%app would have
to be extracted from the expansion of
(go 'a), since lexical
scope would prevent an arbitrary
#%app from capturing.
The act of extracting
#%app removes its certification, whereas
#%app within the expansion is still certified; comparing
these certifications, the macro expander rejects the local-binding
reference, and
unchecked-go remains protected.
In much the same way that the macro expander copies properties from a transformer's input to its output, the expander copies certificates from a transformer's input to its output. Building on the previous example,
(module n
mzscheme(require m) (provide go-more) (define y 'hello) (
define-syntax(go-more stx) #'(go y)))
the expansion of
(go-more) introduces a reference to the
y in
(go y), and a certificate allows
the reference to
y. As
(go y) is expanded to
(unchecked-go 8 y), the certificate that allows
is copied over, in addition to the certificate that allows the
reference to
When a protected identifier becomes inaccessible by direct reference (i.e., when the current code inspector is changed so that it does not control the module's invocation; see section 9.4), the protected identifier is treated like an unexported identifier.
220.127.116.11 Certificate Propagation
When the result of a macro expansion contains a
form, the macro expansion's certificate must be attached to the
resulting syntax object to support macro-generating macros. In
general, when the macro expander encounters
quote-syntax, it
attaches all certificates from enclosing expressions to the quoted
syntax constant. However, the certificates are attached to the syntax
constant as inactive certificates, and inactive certificates
do not count directly for certifying identifier access. Inactive
certificates become active when the macro expander certifies the
result of a macro expansion; at that time, the expander removes all
inactive certificates within the expansion result and attaches active
versions of the certificates to the overall expansion result.
For example, suppose that the
go macro is implemented through
a macro:
(module m
mzscheme(provide def-go) (define (unchecked-go n x) (+ n 17)) (
define-syntax(def-go stx) (syntax-case stx () [(_ go) #'(
define-syntax(go stx) (syntax-case stx () [(_ x) #'(unchecked-go 8 x)]))])))
def-go is used inside another module, the generated
macro should legally generate expressions that
unchecked-go, since
def-go in
m had
complete control over the generated macro.
(module n
mzscheme(require m) (def-go go) (go 10)) ; access to
unchecked-gois allowed
This example works because the expansion of
(def-go go) is
certified to access protected identifiers in
unchecked-go. Specifically, the certified expansion
is a definition of the macro
go, which includes a
syntax-object constant
unchecked-go. Since the enclosing
macro declaration is certified, the
unchecked-go syntax
constant gets an inactive certificate to access protected identifiers
m. When
(go 10) is expanded, the inactive
certificate on
unchecked-go is activated for the macro
(unchecked-go 8 10), and the access
unchecked-go is allowed.
To see why
unchecked-go as a syntax constant must be given an
inactive certificate instead of an active one, it's helpful to write
def-go macro as follows:
define-syntax(def-go stx) (syntax-case stx () [(_ go) #'(
define-syntax(go stx) (syntax-case stx () [(_ x) (with-syntax ([ug (quote-syntax unchecked-go)]) #'(ug 8 x))]))]))
In this case,
unchecked-go is clearly quoted as an immediate
syntax object in the expansion of
(def-go go). If this
syntax object were given an active certificate, then it would keep
the certificate -- directly on the
unchecked-go -- in the
(unchecked-go 8 10). Consequently,
unchecked-go identifier could be extracted and used with
its certificate intact. Attaching an inactive certificate
unchecked-go and activating it only for the complete
(unchecked-go 8 10) ensures
unchecked-go is used only in the way intended by the
implementor of
procedure allows inactive
certificates to be transferred from one syntax object to
another. Such transfers are allowed because a macro transformer with
access to the syntax object could already wrap it with an arbitrary
context before activating the certificates. In practice, transferring
inactive certificates is useful mainly to macros that implement to
new template forms, such as
220.127.116.11 Internal Certificates
In some cases, a macro implementor intends to allow limited
destructuring of a macro result without losing the result's
certificate. For example, given the following
(module q
mzscheme(provide define-like-y) (define y 'hello) (
define-syntax(define-like-y stx) (syntax-case stx () [(_ id) #'(define-values (id) y)])))
someone may use the macro in an internal definition:
(let () (define-like-y x) x)
The implementor of the
q module most likely intended to allow
such uses of
define-like-y. To convert an internal definition
into a
letrec binding, however, the
define form
produced by
define-like-y must be deconstructed, which would
normally lose the certificate that allows the reference to
The internal use of
define-like-y is allowed because the
macro expander treats specially a transformer result that is a syntax
list beginning with
define-values. In that case, instead of
attaching the certificate to the overall expression, the certificate
is instead attached to each individual element of the syntax list,
pushing the certificates into the second element of the list so that
they are attached to the defined identifiers. Thus, a certificate is
attached to
x, and
y in the
expansion result
(define-values (x) y), and the definition
can be deconstructed for conversion to
Just like the new certificate that is added to a transformer result,
old certificates from the input are similarly moved to syntax-list
elements when the result starts with
define-values. Thus,
define-like-y could have been implemented to produce
(define id y), using
define instead of
define-values. In that case, the certificate to allow
reference to
y would be attached initially to the expansion
(define x y), but as the
define is expanded
define-values, the certificate would be moved to the
The macro expander treats syntax-list results starting
define-syntaxes in the same way that it treats results
starting with
define-values. Syntax-list results starting
begin are treated similarly, except that the second
element of the syntax list is treated like all the other elements
(i.e., the certificate is attached to the element instead of its
content). Furthermore, the macro expander applies this special
handling recursively, in case a macro produces a
begin form
that contains nested
define-values forms.
The default application of certificates can be overridden by attaching
'certify-mode property (see section 12.6.2) to the
result syntax object of a macro transformer. If the property value
'opaque, then the certificate is attached to the
syntax object and not its parts. If the property value
'transparent, then the certificate is attached to the
syntax object's parts. If the property value
'transparent-binding, then the certificate is
attached to the syntax object's parts and to the sub-parts of the
second part (as for
define-syntaxes). The
'transparent-binding modes triggers recursive property
checking at the parts, so that the certificate can be pushed
arbitrarily deep into a transformer's result.
126.96.36.199 Checking and Transferring Certificates
In general, a certificate combines a mark (see section 12.6), a
module name (more precisely, a module path index; see
section 5.4.2), an inspector, and an arbitrary key object. Within
a certified syntax object, the certificate's mark is attached to
every piece of syntax that was introduced by the relevant macro
transformation (see again section 12.6), so the certificate
applies only to those pieces of syntax, and only to identifiers that
are bound by the transformer's module. The certificate's inspector
depends on the module that defined the transformer; specifically, it
is the inspector for the module's declaration (see
section 9.4). A certificate's key is hidden if it is
introduced by macro expansion, but applying the result of
syntax-local-certifier (see section 12.6) can introduce
certificates with other keys.
To check access to an unexported identifier, the compiler or macro expander checks each of the identifier's marks and module bindings; if, for some mark, the identifier's enclosing expressions include a certificate with the mark, the identifier's binding module, and with an inspector that controls the module's invocation (as opposed to the module's declaration; see again section 9.4), then the access is allowed. To check access to a protected identifier, only the certificate's mark and inspector are used (i.e., the module that bound the transformer is irrelevant, as long as it was evaluated with a sufficiently powerful inspector). The certificate key is not used in checking references.
To check access to a locally bound identifier, the compiler or macro expander checks the marks of the binding and reference identifiers; for every mark that they have in common, if the reference identifier has a certificate for the mark from an enclosing expression, the binding identifier must have a certificate for the mark from an enclosing expression, otherwise the reference is disallowed. (The reference identifier can have additional certificates for marks that are not attached to the binding identifier.) The binding module (if any) and the certificate key are not used for checking a local reference.
procedure never transfers a
certificate from one syntax object to another, so it cannot be used
to gain access to an unexported identifier. The
syntax-recertify procedure can be used to transfer a
certificate from one syntax object to another, but only if the
certificate's key is provided, or if a sufficiently powerful
inspector is provided. Thus, a certificate's inspector serves two
roles: it determines the certificate's power to grant access, and
also allows the certificate to be moved arbitrarily by anyone with a
more powerful inspector.
new-stx old-stx inspector key-v
) copies certain
certificates of
old-stx to
new-stx: a certificate is
copied if its inspector is either
inspector or controlled
inspector, or if the certificate's key is
otherwise the certificate is not copied. The result is a syntax
object like
new-stx, but with the copied
certificates. (The
new-stx object itself is not modified.) Both
active and inactive certificates are copied.
12.6.4 Information on Structure Types
define-struct form (see section 4.1) binds
the name of a structure type to an expansion-time value that records
the identifiers bound to the structure type, the constructor
procedure, the predicate procedure, and the field accessor and
mutator procedures. This information can be used during the expansion
of other expressions by transformer that call
syntax-local-value (see section 12.6).
For example, the
define-struct variant for subtypes (see
section 4.2) uses the base type name
t to find the
struct containing the base type's
descriptor; it also folds the field accessor and mutator information
for the base type into the information for the subtype. The
match form (see Chapter 27
in PLT MzLib: Libraries Manual) uses a type name to
find the predicates and field accessors for the structure type.
Besides using the information, other syntactic forms can even generate
information with the same shape. For example, the
form in an imported signature for
unit (see
Chapter 55
in PLT MzLib: Libraries Manual) causes the
unit transformer
to generate information about imported structure types, so that
match and subtyping
define-struct expressions work
within the unit.
The expansion-time information for a structure type is represented as an immutable list of six items:
an identifier that is bound to the structure type's descriptor, or
#fit none is known;
an identifier that is bound to the structure type's constructor, or
#fit none is known;
an identifier that is bound to the structure type's predicate, or
#fit none is known;
an immutable list of identifiers bound to the field accessors of the structure type, optionally with
#fas the list's last element. A
#fas the last element indicates that the structure type may have additional fields, otherwise the list is a reliable indicator of the number of fields in the structure type. Furthermore, the accessors are listed in reverse order for the corresponding constructor arguments. (The reverse order enables sharing in the lists for a subtype and its base type.)
an immutable list of identifiers bound to the field mutators of the structure type, or
#ffor each field that has no known mutator, and optionally with an extra
#fas the list's last element (if the accessor list has such a
#f). The list's order and the meaning of a final
#fare the same as for the accessor identifiers, and the length of the mutator list is the same as the accessor list's length.
an identifier that determines a super-type for the structure type,
#fif the super-type (if any) is unknown, or
#tif there is no super-type. If a super-type is specified, the identifier is also bound to structure-type expansion-time information.
The implementor of a syntactic form can expect users of the form to
know what kind of information is available about a structure
type. For example, the
match implementation works with
structure information containing an incomplete set of accessor
bindings, because the user is assumed to know what information is
available in the context of the
match expression. In
particular, the
match expression can appear in a
unit form with an imported structure type, in which case
the user is expected to know the set of fields that are listed in the
signature for the structure type.
12.6.5 Information on Expanded and Compiled Modules
MzScheme provides an interface for obtaining information about an expanded or compiled module declaration's imports and exports. This information is intended for use by tools such as a compilation manager.
Information for an expanded module declaration is stored in a set of properties attached to the syntax object:
'module-direct-requires-- an immutable list of module path indices (or symbols) representing the modules explicitly imported into the module.
'module-direct-for-syntax-requires-- an immutable list of module path indices (or symbols) representing the modules explicitly for-syntax imported into the module.
'module-direct-for-template-requires-- an immutable list of module path indices (or symbols; see section 5.4.2) representing the modules explicitly for-template imported into the module.
'module-variable-provides-- an immutable list of provided items, where each item is one of the following:
symbol-- represents a locally defined variable that is provided with its defined name.
(cons-immutable-- represents a locally defined variable that is provided with renaming; the first symbol is the exported name, and the second symbol is the defined name.
(list*-immutable-- represents a re-exported and possibly re-named variable from the specified module;
module-path-indexis either an index or symbol (see section 5.4.2), indicating the source module for the binding. The
provided-symbolis the external name for the re-export, and
defined-symbolis the originally defined name in the module specified by
'module-syntax-provides-- like
'module-variable-provides, but for syntax exports instead of variable exports.
'module-indirect-provides-- an immutable list of symbols for variables that are defined in the module but not exported; they may be exported indirectly through macro expansions. Definitions of macro-generated identifiers create uninterned symbols in this list.
'module-kernel-reprovide-hint-- either
#t, or a symbol. If it is
#t, then the module re-exports all of the functionality from MzScheme's internal kernel module. If it is a symbol, then all kernel exports but the indicated one is re-exported, and some other export is provided with the indicated name. This ad hoc information is used in an optimization by the mzc compiler.
'module-self-path-index-- a module path index (see section 5.4.2) whose parts are both
#f. This information is used by the mzc compiler to manage syntax objects (which contain module-relative information keyed on the module's own index).
) returns
#t if
v is
a compiled expression for a
module declaration,
otherwise. See also section 14.3.
) takes a module
declaration in compiled form (see section 14.3) and returns a
symbol for the module's declared name.
) takes a module
declaration in compiled form (see section 14.3) and returns
four immutable lists of module path indices (and symbols; see
section 5.4.2): one for the module's explicit imports, one for
the module's explicit for-syntax imports, one for the module's
explicit for-template imports, and one for the module's explicit
for-label imports.
) takes a module
declaration in compiled form (see section 14.3) and returns
six immutable lists of symbols: one for the module's explicit
variable exports, one for the module's explicit syntax exports, one
for the module's explicit for-syntax variable exports, one for the
module's explicit for-syntax syntax exports, one for the module's
explicit for-label variable exports, and one for the module's
explicit for-label syntax exports.
45 In general, modules and for-syntax imports create a hierarchy of run times and expansion times. See section 12.3.4 for more information.
46 In this
particular case, Shriram Krishnamurthi points out changing
if-it to use
(datum->syntax-object (
solves the problem in a sensible way.
47 In contrast, a namespace
created by
(scheme-report-environment imports only
syntax-rules into the transformer environment.
48 More precisely, the property is attached by the default read handler in syntax mode when using the default readtable.


text:
ADMIN: Add avatars to your TLC comments
Nov 28, 2004
We're happy to announce that we've implemented Gravatar into our comments system, a feature that allows you to add an avatar of your choosing to your comments (see B.K.'s example here).
Here's how it works. Go to Gravatar and sign up for a free account. Upload an 80×80 pixel avatar into their system; they will rate it similar to the way movies are rated (only G-rated ones are allowed here, folks). Then, when you comment on TLC, all you need to do is enter your correct e-mail address into the box that asks for it, and our site will connect with Gravatar, find the avatar that matches your email address, and post it next to your comment. Neat, huh?

subset: commoncrawl


text:
Create your guild site for any game.
View a demonstration guild site.
Discuss ideas and ask questions on our support message forums.
Find out more about our features.
Guild Website Hosting Packages
Free Guild Hosting — FREE!
- home page with roster and news
- guild forums
- in-game module for roster update, item auctions, raid queue management*
- item hovers for World of Warcraft sites, such as Dislodged Foreign Object, Shadowmourne, and Lil' XT
- item hovers for Aion sites, such as Noble Dionae's Earrings, Narka's Plate Boots, and Hot Heart of Magic
- 10 MB of file hosting
- upgradeable to Basic or Pro package at any time
- your own subdomain, such as yourguild.guildomatic.com
Basic Guild Hosting — As low as $4.99/month
- no ads
- everything in the Free package
- raid calendar
- guild applications/recruitment
- boss progression*
- 500 MB of file hosting
- upgrade to Pro at any time
Pro Guild Hosting — As low as $7.99/month
- everything in the Basic package
- in-game module raid snapshots, dkp support*
- HeadCount module integration
- item drop history
- raid summaries and history
- DKP pages for your guild and members
- complete DKP system
- 3 GB of file hosting
Ventrilo — voice server for guild communication with status hover showing who's online integrated into your guild home page.
Custom Domain — host your guild site under a domain you already own, or buy one and set it up through us.
Included with all Guild Hosting Packages
- 24x7 hosting at a premier colocation facility
- daily backups of your guild data
- quick-turnaround support from our staff for your guild site
- template changes and additions for forums
- our hosted application service means you'll never have to perform any software installation or system maintenance work
- free import service for your previous phpBB2/phpBB3-based message forums
* Currently only available for World of Warcraft guild sites.