Skip to content

Commit

Permalink
Update macro tutorial to recognize item/statement macros and be clearer
Browse files Browse the repository at this point in the history
about invocation location vs. interpolation location.
  • Loading branch information
paulstansifer authored and catamorphism committed Dec 6, 2012
1 parent 14a7be3 commit d0c2d6c
Showing 1 changed file with 27 additions and 6 deletions.
33 changes: 27 additions & 6 deletions doc/tutorial-macros.md
Expand Up @@ -84,23 +84,44 @@ To take as an argument a fragment of Rust code, write `$` followed by a name
* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)

The parser interprets any token that's not preceded by a `$` literally. Rust's usual
rules of tokenization apply,

So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
that could be invoked like: `my_macro!(i->(( 2+2 )))`.

## Invocation location

A macro invocation may take the place of (and therefore expand to) either an
expression, an item, or a statement. The Rust parser will parse the macro
invocation as a "placeholder" for whichever of those three nonterminals is
appropriate for the location.

At expansion time, the output of the macro will be parsed as whichever of the
three nonterminals it stands in for. This means that a single macro might,
for example, expand to an item or an expression, depending on its arguments
(and cause a syntax error if it is called with the wrong argument for its
location). Although this behavior sounds excessively dynamic, it is known to
be useful under some circumstances.


# Transcription syntax

The right-hand side of the `=>` follows the same rules as the left-hand side,
except that a `$` need only be followed by the name of the syntactic fragment
to transcribe into the macro expansion; its type need not be repeated.

The right-hand side must be enclosed by delimiters, and must be
an expression. Currently, invocations of user-defined macros can only appear in a context
where the Rust grammar requires an expression, even though `macro_rules!` itself can appear
in a context where the grammar requires an item.
The right-hand side must be enclosed by delimiters, which are ignored by the
transcriber (therefore `() => ((1,2,3))` is a macro that expands to a tuple
expression, `() => (let $x=$val)` is a macro that expands to a statement, and
`() => (1,2,3)` is a macro that expands to a syntax errror).

## Interpolation location

The interpolation `$argument_name` may appear in any location consistent with
its fragment specifier (i.e., if it is specified as `ident`, it may be used
anywhere an identifier is permitted).

# Multiplicity

Expand Down Expand Up @@ -163,7 +184,7 @@ fragments by the macro parser:
fragment. For example, if the comma were omitted from the syntax of
`early_return!` above, `input_1 [` would've been interpreted as the beginning
of an array index. In fact, invoking the macro would have been impossible.
2. The parser must have eliminated all ambiguity by the time it reaches a
2. The parser must have eliminated all ambiguity by the time it reaches a
`$name:fragment_specifier` declaration. This limitation can result in parse
errors when declarations occur at the beginning of, or immediately after,
a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to
Expand Down

0 comments on commit d0c2d6c

Please sign in to comment.