Skip to content

Commit

Permalink
Merge pull request #458 from ehuss/grammar-macro
Browse files Browse the repository at this point in the history
Grammar: macros
  • Loading branch information
matthewjasper authored Nov 3, 2018
2 parents 803412c + 3e7bb14 commit 34c92dd
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 42 deletions.
2 changes: 2 additions & 0 deletions src/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
>       | [_BreakExpression_]\
>       | [_RangeExpression_]\
>       | [_ReturnExpression_]\
>       | [_MacroInvocation_]\
>    )
>
> _ExpressionWithBlock_ :\
Expand Down Expand Up @@ -341,6 +342,7 @@ They are never allowed before:
[_LazyBooleanExpression_]: expressions/operator-expr.html#lazy-boolean-operators
[_LiteralExpression_]: expressions/literal-expr.html
[_LoopExpression_]: expressions/loop-expr.html
[_MacroInvocation_]: macros.html#macro-invocation
[_MatchExpression_]: expressions/match-expr.html
[_MethodCallExpression_]: expressions/method-call-expr.html
[_OperatorExpression_]: expressions/operator-expr.html
Expand Down
16 changes: 13 additions & 3 deletions src/items.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

> **<sup>Syntax:<sup>**\
> _Item_:\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> [_Visibility_]<sup>?</sup>\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup>\
> &nbsp;&nbsp; &nbsp;&nbsp; _VisItem_\
> &nbsp;&nbsp; | _MacroItem_
>
> _VisItem_:\
> &nbsp;&nbsp; [_Visibility_]<sup>?</sup>\
> &nbsp;&nbsp; (\
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_Module_]\
> &nbsp;&nbsp; &nbsp;&nbsp; | [_ExternCrate_]\
Expand All @@ -17,9 +22,12 @@
> &nbsp;&nbsp; &nbsp;&nbsp; | [_Trait_]\
> &nbsp;&nbsp; &nbsp;&nbsp; | [_Implementation_]\
> &nbsp;&nbsp; &nbsp;&nbsp; | [_ExternBlock_]\
> &nbsp;&nbsp; &nbsp;&nbsp; | _Macro_\
> &nbsp;&nbsp; &nbsp;&nbsp; | _MacroDefinition_\
> &nbsp;&nbsp; )
>
> _MacroItem_:\
> &nbsp;&nbsp; &nbsp;&nbsp; [_MacroInvocationSemi_]\
> &nbsp;&nbsp; | [_MacroRulesDefinition_]

An _item_ is a component of a crate. Items are organized within a crate by a
nested set of [modules]. Every crate has a single "outermost" anonymous module;
Expand Down Expand Up @@ -61,6 +69,8 @@ which sub-item declarations may appear.
[_ExternCrate_]: items/extern-crates.html
[_Function_]: items/functions.html
[_Implementation_]: items/implementations.html
[_MacroInvocationSemi_]: macros.html#macro-invocation
[_MacroRulesDefinition_]: macros-by-example.html
[_Module_]: items/modules.html
[_OuterAttribute_]: attributes.html
[_StaticItem_]: items/static-items.html
Expand Down
15 changes: 9 additions & 6 deletions src/items/implementations.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
> &nbsp;&nbsp; `}`
>
> _InherentImplItem_ :\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup>\
> &nbsp;&nbsp; [_Visibility_]<sup>?</sup>\
> &nbsp;&nbsp; ( [_ConstantItem_] | [_Function_] | [_Method_] )
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> (\
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_MacroInvocationSemi_]\
> &nbsp;&nbsp; &nbsp;&nbsp; | ( [_Visibility_]<sup>?</sup> ( [_ConstantItem_] | [_Function_] | [_Method_] ) )\
> &nbsp;&nbsp; )
>
> _TraitImpl_ :\
> &nbsp;&nbsp; `unsafe`<sup>?</sup> `impl` [_Generics_] `!`<sup>?</sup>
Expand All @@ -25,9 +26,10 @@
> &nbsp;&nbsp; `}`
>
> _TraitImplItem_ :\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup>\
> &nbsp;&nbsp; [_Visibility_]<sup>?</sup>\
> &nbsp;&nbsp; ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] | [_Method_] )
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> (\
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_MacroInvocationSemi_]\
> &nbsp;&nbsp; &nbsp;&nbsp; | ( [_Visibility_]<sup>?</sup> ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] | [_Method_] ) )\
> &nbsp;&nbsp; )
An _implementation_ is an item that associates items with an _implementing type_.
Implementations are defined with the keyword `impl` and contain functions
Expand Down Expand Up @@ -180,6 +182,7 @@ attributes].
[_Function_]: items/functions.html
[_Generics_]: items/generics.html
[_InnerAttribute_]: attributes.html
[_MacroInvocationSemi_]: macros.html#macro-invocation
[_Method_]: items/associated-items.html#methods
[_OuterAttribute_]: attributes.html
[_TypeAlias_]: items/type-aliases.html
Expand Down
9 changes: 8 additions & 1 deletion src/items/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@
> &nbsp;&nbsp; `}`
>
> _TraitItem_ :\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> (_TraitFunc_ | _TraitMethod_ | _TraitConst_ | _TraitType_)
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> (\
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; _TraitFunc_\
> &nbsp;&nbsp; &nbsp;&nbsp; | _TraitMethod_\
> &nbsp;&nbsp; &nbsp;&nbsp; | _TraitConst_\
> &nbsp;&nbsp; &nbsp;&nbsp; | _TraitType_\
> &nbsp;&nbsp; &nbsp;&nbsp; | [_MacroInvocationSemi_]\
> &nbsp;&nbsp; )
>
> _TraitFunc_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; _TraitFunctionDecl_ ( `;` | [_BlockExpression_] )
Expand Down Expand Up @@ -205,6 +211,7 @@ trait T {
[_FunctionQualifiers_]: items/functions.html
[_FunctionReturnType_]: items/functions.html
[_Generics_]: items/generics.html
[_MacroInvocationSemi_]: macros.html#macro-invocation
[_OuterAttribute_]: attributes.html
[_Pattern_]: patterns.html
[_SelfParam_]: items/associated-items.html#methods
Expand Down
125 changes: 96 additions & 29 deletions src/macros-by-example.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
# Macros By Example

> **<sup>Syntax</sup>**\
> _MacroRulesDefinition_ :\
> &nbsp;&nbsp; `macro_rules` `!` [IDENTIFIER] _MacroRulesDef_
>
> _MacroRulesDef_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `(` _MacroRules_ `)` `;`\
> &nbsp;&nbsp; | `[` _MacroRules_ `]` `;`\
> &nbsp;&nbsp; | `{` _MacroRules_ `}`
>
> _MacroRules_ :\
> &nbsp;&nbsp; _MacroRule_ ( `;` _MacroRule_ )<sup>\*</sup> `;`<sup>?</sup>
>
> _MacroRule_ :\
> &nbsp;&nbsp; _MacroMatcher_ `=>` _MacroTranscriber_
>
> _MacroMatcher_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `(` _MacroMatch_<sup>\*</sup> `)`\
> &nbsp;&nbsp; | `[` _MacroMatch_<sup>\*</sup> `]`\
> &nbsp;&nbsp; | `{` _MacroMatch_<sup>\*</sup> `}`
>
> _MacroMatch_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; [_Token_]<sub>_except $ and delimiters_</sub>\
> &nbsp;&nbsp; | _MacroMatcher_\
> &nbsp;&nbsp; | `$` [IDENTIFIER] `:` _MacroFragSpec_\
> &nbsp;&nbsp; | `$` `(` _MacroMatch_<sup>+</sup> `)` _MacroRepSep_<sup>?</sup> _MacroKleeneOp_
>
> _MacroFragSpec_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `block` | `expr` | `ident` | `item` | `lifetime`\
> &nbsp;&nbsp; | `meta` | `pat` | `path` | `stmt` | `tt` | `ty` | `vis`
>
> _MacroRepSep_ :\
> &nbsp;&nbsp; [_Token_]<sub>_except delimiters and kleene operators_</sub>
>
> _MacroKleeneOp_<sub>2015</sub> :\
> &nbsp;&nbsp; `*` | `+`
>
> _MacroKleeneOp_<sub>2018+</sub> :\
> &nbsp;&nbsp; `*` | `+` | `?`
>
> _MacroTranscriber_ :\
> &nbsp;&nbsp; [_DelimTokenTree_]
`macro_rules` allows users to define syntax extension in a declarative way. We
call such extensions "macros by example" or simply "macros".

Currently, macros can expand to expressions, statements, items, or patterns.

(A `sep_token` is any token other than `*` and `+`. A `non_special_token` is
any token other than a delimiter or `$`.)
Macros can expand to expressions, statements, items, types, or patterns.

The macro expander looks up macro invocations by name, and tries each macro
rule in turn. It transcribes the first successful match. Matching and
Expand All @@ -20,31 +59,32 @@ balanced, but they are otherwise not special.
In the matcher, `$` _name_ `:` _designator_ matches the nonterminal in the Rust
syntax named by _designator_. Valid designators are:

* `item`: an [item]
* `block`: a [block]
* `stmt`: a [statement]
* `pat`: a [pattern]
* `expr`: an [expression]
* `ty`: a [type]
* `ident`: an [identifier] or [keyword]
* `path`: a [path]
* `tt`: a token tree (a single [token] by matching `()`, `[]`, or `{}`)
* `meta`: the contents of an [attribute]
* `lifetime`: a lifetime. Examples: `'static`, `'a`.
* `vis`: a (visibility qualifier)[visibility-and-privacy]

[item]: items.html
[block]: expressions/block-expr.html
[statement]: statements.html
[pattern]: patterns.html
[expression]: expressions.html
[type]: types.html
[identifier]: identifiers.html
[keyword]: keywords.html
[path]: paths.html
* `item`: an [_Item_]
* `block`: a [_BlockExpression_]
* `stmt`: a [_Statement_] without the trailing semicolon
* `pat`: a [_Pattern_]
* `expr`: an [_Expression_]
* `ty`: a [_Type_]
* `ident`: an [IDENTIFIER_OR_KEYWORD]
* `path`: a [_TypePath_] style path
* `tt`: a [_TokenTree_]&nbsp;(a single [token] or tokens in matching delimiters `()`, `[]`, or `{}`)
* `meta`: a [_MetaItem_], the contents of an attribute
* `lifetime`: a [LIFETIME_TOKEN]
* `vis`: a [_Visibility_] qualifier

[IDENTIFIER_OR_KEYWORD]: identifiers.html
[LIFETIME_TOKEN]: tokens.html#lifetimes-and-loop-labels
[_BlockExpression_]: expressions/block-expr.html
[_Expression_]: expressions.html
[_Item_]: items.html
[_MetaItem_]: attributes.html
[_Pattern_]: patterns.html
[_Statement_]: statements.html
[_TokenTree_]: macros.html#macro-invocation
[_TypePath_]: paths.html#paths-in-types
[_Type_]: types.html
[_Visibility_]: visibility-and-privacy.html
[token]: tokens.html
[attribute]: attributes.html
[visibility-and-privacy]: visibility-and-privacy.html

In the transcriber, the
designator is already known, and so only the name of a matched nonterminal comes
Expand Down Expand Up @@ -94,9 +134,36 @@ Rust syntax is restricted in two ways:
a macro definition like `$i:expr [ , ]` is not legal, because `[` could be part
of an expression. A macro definition like `$i:expr,` or `$i:expr;` would be legal,
however, because `,` and `;` are legal separators. See [RFC 550] for more information.
Specifically:

* `expr` and `stmt` may only be followed by one of `=>`, `,`, or `;`.
* `pat` may only be followed by one of `=>`, `,`, `=`, `|`, `if`, or `in`.
* `path` and `ty` may only be followed by one of `=>`, `,`, `=`, `|`, `;`,
`:`, `>`, `>>`, `[`, `{`, `as`, `where`, or a macro variable of `block`
fragment type.
* `vis` may only be followed by one of `,`, `priv`, a raw identifier, any
token that can begin a type, or a macro variable of `ident`, `ty`, or
`path` fragment type.
* All other fragment types have no restrictions.

2. The parser must have eliminated all ambiguity by the time it reaches a `$`
_name_ `:` _designator_. This requirement most often affects name-designator
pairs when they occur at the beginning of, or immediately after, a `$(...)*`;
requiring a distinctive token in front can solve the problem.
requiring a distinctive token in front can solve the problem. For example:

```rust
// The matcher `$($i:ident)* $e:expr` would be ambiguous because the parser
// would be forced to choose between an identifier or an expression. Use some
// token to distinguish them.
macro_rules! example {
($(I $i:ident)* E $e:expr) => { ($($i)-*) * $e };
}
let foo = 2;
let bar = 3;
// The following expands to `(foo - bar) * 5`
example!(I foo I bar E 5);
```

[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md
[_DelimTokenTree_]: macros.html
[_Token_]: tokens.html
89 changes: 89 additions & 0 deletions src/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,95 @@ There are two ways to define new macros:
* [Macros by Example] define new syntax in a higher-level, declarative way.
* [Procedural Macros] can be used to implement custom derive.

## Macro Invocation

> **<sup>Syntax</sup>**\
> _MacroInvocation_ :\
> &nbsp;&nbsp; [_SimplePath_] `!` _DelimTokenTree_
>
> _DelimTokenTree_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `(` _TokenTree_<sup>\*</sup> `)`\
> &nbsp;&nbsp; | `[` _TokenTree_<sup>\*</sup> `]`\
> &nbsp;&nbsp; | `{` _TokenTree_<sup>\*</sup> `}`
>
> _TokenTree_ :\
> &nbsp;&nbsp; [_Token_]<sub>_except delimiters_</sub> | _DelimTokenTree_
>
> _MacroInvocationSemi_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; [_SimplePath_] `!` `(` _TokenTree_<sup>\*</sup> `)` `;`\
> &nbsp;&nbsp; | [_SimplePath_] `!` `[` _TokenTree_<sup>\*</sup> `]` `;`\
> &nbsp;&nbsp; | [_SimplePath_] `!` `{` _TokenTree_<sup>\*</sup> `}`
A macro invocation executes a macro at compile time and replaces the
invocation with the result of the macro. Macros may be invoked in the
following situations:

* [Expressions] and [statements]
* [Patterns]
* [Types]
* [Items] including [associated items]
* [`macro_rules`] transcribers

When used as an item or a statement, the _MacroInvocationSemi_ form is used
where a semicolon is required at the end when not using curly braces.
[Visibility qualifiers] are never allowed before a macro invocation or
[`macro_rules`] definition.

```rust
// Used as an expression.
let x = vec![1,2,3];

// Used as a statement.
println!("Hello!");

// Used in a pattern.
macro_rules! pat {
($i:ident) => (Some($i))
}

if let pat!(x) = Some(1) {
assert_eq!(x, 1);
}

// Used in a type.
macro_rules! Tuple {
{ $A:ty, $B:ty } => { ($A, $B) };
}

type N2 = Tuple!(i32, i32);

// Used as an item.
# use std::cell::RefCell;
thread_local!(static FOO: RefCell<u32> = RefCell::new(1));

// Used as an associated item.
macro_rules! const_maker {
($t:ty, $v:tt) => { const CONST: $t = $v; };
}
trait T {
const_maker!{i32, 7}
}

// Macro calls within macros.
macro_rules! example {
() => { println!("Macro call in a macro!") };
}
// Outer macro `example` is expanded, then inner macro `println` is expanded.
example!();
```

[Macros by Example]: macros-by-example.html
[Procedural Macros]: procedural-macros.html
[_SimplePath_]: paths.html#simple-paths
[_Token_]: tokens.html
[associated items]: items/associated-items.html
[compiler plugins]: ../unstable-book/language-features/plugin.html
[delimiters]: tokens.html#delimiters
[expressions]: expressions.html
[items]: items.html
[`macro_rules`]: macros-by-example.html
[patterns]: patterns.html
[statements]: statements.html
[tokens]: tokens.html
[types]: types.html
[visibility qualifiers]: visibility-and-privacy.html
4 changes: 3 additions & 1 deletion src/patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
> &nbsp;&nbsp; | [_TuplePattern_]\
> &nbsp;&nbsp; | [_GroupedPattern_]\
> &nbsp;&nbsp; | [_SlicePattern_]\
> &nbsp;&nbsp; | [_PathPattern_]
> &nbsp;&nbsp; | [_PathPattern_]\
> &nbsp;&nbsp; | [_MacroInvocation_]
Patterns are used to match values against structures and to,
optionally, bind variables to values inside these structures. They are also
Expand Down Expand Up @@ -653,6 +654,7 @@ refer to refutable constants or enum variants for enums with multiple variants.
[_GroupedPattern_]: #grouped-patterns
[_IdentifierPattern_]: #identifier-patterns
[_LiteralPattern_]: #literal-patterns
[_MacroInvocation_]: macros.html#macro-invocation
[_PathInExpression_]: paths.html#paths-in-expressions
[_PathPattern_]: #path-patterns
[_Pattern_]: #patterns
Expand Down
4 changes: 3 additions & 1 deletion src/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
> &nbsp;&nbsp; &nbsp;&nbsp; `;`\
> &nbsp;&nbsp; | [_Item_]\
> &nbsp;&nbsp; | [_LetStatement_]\
> &nbsp;&nbsp; | [_ExpressionStatement_]
> &nbsp;&nbsp; | [_ExpressionStatement_]\
> &nbsp;&nbsp; | [_MacroInvocationSemi_]

A *statement* is a component of a [block], which is in turn a component of an
Expand Down Expand Up @@ -130,6 +131,7 @@ statement are [`cfg`], and [the lint check attributes].
[_Expression_]: expressions.html
[_Item_]: items.html
[_LetStatement_]: #let-statements
[_MacroInvocationSemi_]: macros.html#macro-invocation
[_OuterAttribute_]: attributes.html
[_Pattern_]: patterns.html
[_Type_]: types.html
Loading

0 comments on commit 34c92dd

Please sign in to comment.