[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