[R6RS] SYNTAX-CASE
dyb at cs.indiana.edu
dyb
Fri Apr 1 10:51:46 EST 2005
In the interest of moving forward while Manuel considers how we might
create a compatible general-purpose matcher, I would like for us to vote
to include syntax-case while leaving open the possibility of changing
the pattern matcher at a later time. In other words, I'd like for us
to have, by default, a subset of syntax-case essentially as it exists
today, so that we have some version of it in R6RS even if we fail to
come up with a compatible general matcher.
An alternative is to wait until after we've succeeded in coming up
with a compatible general matcher or given up the attempt to do so,
but I feel like time is passing quickly and we need to start reaching
closure on this and other issues.
I've included below a revised version of the proposal I sent out before
the Utah meeting, amended as Matthew and I (the macro subcommittee)
agreed at the Utah meeting. It also accounts for the declaration of
indirect exports (what we had been calling implicit exports). The latter
can go away if we don't agree on a module system.
If we decide to include syntax-case, I will write a more formal
description and post it to the twiki.
Kent
--------
I propose we make the following changes/additions to the r5rs macro
system for r6rs:
Syntax objects:
Syntax objects are opaque datatypes. Syntax objects may be created
by the expander or by the programmer via the syntax form or
datum->syntax-object (see below). Syntax objects represent program
fragments and sufficient information to place identifiers contained
within those fragments in their proper lexical context.
Syntax objects may be coerced to data via syntax-object->datum
(see below).
Terminology note: a syntax-object representing an identifier is
referred to as an identifier.
Transformers:
define-syntax, let-syntax, or letrec-syntax right-hand-sides are
transformers. A transformer is an expression that evaluates (at
expansion time) to a procedure of one argument. The expander
applies a transformer to a syntax object representing the input
form.
note: we may want the transformer to take two arguments: a syntax object
and a compile-time environment, provide a mechanism for extracting
bindings from the environment, and specify abstractly what the bindings
look like. We would presumably also want to extend define-syntax and
company right-hand sides to allow extended bindings to be placed into
the compile-time environment.
define-syntax:
No change in syntax, but allow define-syntax to appear wherever other
definitions can appear
indirect-export:
(indirect-export keyword identifier ...) is a declaration to the
module system that the transformer associated with keyword may
insert references to one or more of identifier .... If keyword is
directly or indirectly exported by a module, then identifier ...
are indirectly exported. Identifiers that are indirectly exported
and not separately directly exported can be referenced or assigned
only by the code produced by an exported transformer.
note: this can go away if we don't agree on module system. if we do
agree on a module system, it may be better to describe this form
with the module system.
syntax-rules
syntax-rules evaluates to a procedure of one argument.
syntax-rules is as in r5rs with the following extensions:
- Patterns are generalized slightly to allow a fixed number of
subpatterns to appear after an ellipsis, e.g., (x ... y z).
- Underscores are anonymous pattern variables that match anything
but are not bound to anything.
- An optional fender may appear between the pattern and
template of any clause. the clause is chosen only if the
pattern matches the input and (if present) the fender
evaluates to a non-false value. within the fender, the
pattern variables appearing within the pattern are bound
to the corresponding pieces of the input.
syntax-rules may be defined as a macro in terms of syntax-case.
syntax-case
syntax-case has the following syntax:
(syntax-case expr (literal ...) clause ...)
where clause takes one of the two forms below.
(pattern output-expr)
(pattern fender output-expr)
(literal ...) and fenders are as in syntax-rules.
syntax-case evaluates expr, which must evaluate to a syntax object,
then attempts to find a matching clause by trying each pattern
and, for patterns that match, fender in turn.
The pattern variables of the matching clause are bound to the
corresponding pieces of the input within output-expr.
Patterns are similar to syntax-rules patterns except that the
pattern need not be list structured and, if list structured,
the first subform is not treated specially.
The following transformers for or are equivalent:
(syntax-rules ()
((_) #f)
((_ e) e)
((_ e1 e2 ...) (let ((t e1)) (if t t (or e2 ...)))))
(lambda (x)
(syntax-case x ()
((_) #'#f)
((_ e) #'e)
((_ e1 e2 ...) #'(let ((t e1)) (if t t (or e2 ...))))))
syntax
A syntax form, written as (syntax datum) or #'datum, evaluates to a
syntax object representing datum, with embedded pattern variables
lexically visible where the syntax form appears replaced by their
values. Ellipses are used as in syntax-rules templates. Information
necessary to place each identifier (except pattern variables replaced
as described above) in the lexical context of the syntax form is
incorporated into the syntax object.
syntax-object?
is bound to a procedure that takes a single argument. If the argument
is a syntax-object, it returns #t, otherwise it returns #f.
syntax-object->datum
is bound to a procedure that takes a single argument, which must be
a syntax-object. It returns a datum representing the syntax object.
All lexical-context information associated with embedded identifiers
is lost.
datum->syntax-object
is bound to a procedure of two arguments. The first is a template
identifier and the second is an arbitrary value. datum->syntax-object
converts the value into a syntax object with all of the information
necessary to make the object appear to the expander as if it appeared
in the source or macro output where and when the template identifier
first appeared.
generate-temporaries
is bound to a procedure of one argument. The argument must be a
proper list, the contents of which is of no consequence.
generate-temporaries returns a list of unique identifiers as long
as the input list.
identifier?
is bound to a procedure of one argument. It returns true if the
argument is an identifier (syntax object representing an identifier),
otherwise false.
bound-identifier=?
is bound to a procedure of two arguments, which must both be
identifiers. It returns true if a binding for either in the output
of a macro would capture references to the other.
free-identifier=?
is bound to a procedure of two arguments, which must both be
identifiers. It returns true if the two identifiers would refer
to the same binding if inserted into the output of a macro as
free identifiers.
note: we may also need literal-identifier=? if we add modules
identifier-syntax
identifier-syntax is an additional way to define transformers for
simulated variables. It takes one of the following two forms:
(identifier-syntax template)
(identifier-syntax
[id template]
[(set! id expr) template])
note: we probably want a lower-level version of this as supported
by both Chez Scheme and MzScheme.
with-syntax
with-syntax is a local binding construct (like let) for pattern
variables. It takes the following form:
(with-syntax ((pattern expr) ...) expr)
e.g.,
(with-syntax ((a 1) ((b ...) '(2 3 4))) #'(a b ...)) => (1 2 3 4)
it is may be defined as a macro in terms of syntax-case.
Note:
We may also want to consider adding fluid-let-syntax
More information about the R6RS
mailing list