From 0c12690eed4c9818bfefe99b07659277089d12ee Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 9 Oct 2018 16:41:36 -0700 Subject: [PATCH 1/3] Grammar: macros --- src/expressions.md | 2 + src/items.md | 8 +++- src/items/implementations.md | 7 ++- src/items/traits.md | 9 +++- src/macros-by-example.md | 90 +++++++++++++++++++++++++++++++----- src/macros.md | 88 +++++++++++++++++++++++++++++++++++ src/patterns.md | 4 +- src/statements.md | 4 +- src/types.md | 4 +- 9 files changed, 197 insertions(+), 19 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 91985c2a8fbbb..fc6104a442fd6 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -26,6 +26,7 @@ >       | [_BreakExpression_]\ >       | [_RangeExpression_]\ >       | [_ReturnExpression_]\ +>       | [_MacroInvocation_]\ >    ) > > _ExpressionWithBlock_ :\ @@ -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 diff --git a/src/items.md b/src/items.md index 65bcf8782f2c9..88e6eaf151c7d 100644 --- a/src/items.md +++ b/src/items.md @@ -17,8 +17,8 @@ >       | [_Trait_]\ >       | [_Implementation_]\ >       | [_ExternBlock_]\ ->       | _Macro_\ ->       | _MacroDefinition_\ +>       | [_MacroInvocationSemi_] [^novis]\ +>       | [_MacroRulesDefinition_] [^novis]\ >    ) An _item_ is a component of a crate. Items are organized within a crate by a @@ -55,12 +55,16 @@ qualified by the name of the enclosing item, or is private to the enclosing item (in the case of functions). The grammar specifies the exact locations in which sub-item declarations may appear. +[^novis]: Macros may not start with a visibility modifier. + [_ConstantItem_]: items/constant-items.html [_Enumeration_]: items/enumerations.html [_ExternBlock_]: items/external-blocks.html [_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 diff --git a/src/items/implementations.md b/src/items/implementations.md index 8cdef82973b63..f76686bd45ac1 100644 --- a/src/items/implementations.md +++ b/src/items/implementations.md @@ -13,7 +13,7 @@ > _InherentImplItem_ :\ >    [_OuterAttribute_]\*\ >    [_Visibility_]?\ ->    ( [_ConstantItem_] | [_Function_] | [_Method_] ) +>    ( [_ConstantItem_] | [_Function_] | [_Method_] | [_MacroInvocationSemi_] [^novis] ) > > _TraitImpl_ :\ >    `unsafe`? `impl` [_Generics_] `!`? @@ -27,7 +27,7 @@ > _TraitImplItem_ :\ >    [_OuterAttribute_]\*\ >    [_Visibility_]?\ ->    ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] | [_Method_] ) +>    ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] | [_Method_] | [_MacroInvocationSemi_] [^novis] ) An _implementation_ is an item that associates items with an _implementing type_. Implementations are defined with the keyword `impl` and contain functions @@ -175,11 +175,14 @@ attributes must come before any associated items. That attributes that have meaning here are [`cfg`], [`deprecated`], [`doc`], and [the lint check attributes]. +[^novis]: Macro invocations may not start with a visibility modifier. + [IDENTIFIER]: identifiers.html [_ConstantItem_]: items/constant-items.html [_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 diff --git a/src/items/traits.md b/src/items/traits.md index 6b14f540bbacb..4323ecd6b8e11 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -9,7 +9,13 @@ >    `}` > > _TraitItem_ :\ ->    [_OuterAttribute_]\* (_TraitFunc_ | _TraitMethod_ | _TraitConst_ | _TraitType_) +>    [_OuterAttribute_]\* (\ +>          _TraitFunc_\ +>       | _TraitMethod_\ +>       | _TraitConst_\ +>       | _TraitType_\ +>       | [_MacroInvocationSemi_]\ +>    ) > > _TraitFunc_ :\ >       _TraitFunctionDecl_ ( `;` | [_BlockExpression_] ) @@ -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 diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 0cebc8d559051..517102aa68ee4 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -1,12 +1,51 @@ # Macros By Example +> **Syntax**\ +> _MacroRulesDefinition_ :\ +>    `macro_rules` `!` [IDENTIFIER] _MacroRulesDef_ +> +> _MacroRulesDef_ :\ +>       `(` _MacroRules_ `)` `;`\ +>    | `[` _MacroRules_ `]` `;`\ +>    | `{` _MacroRules_ `}` +> +> _MacroRules_ :\ +>    _MacroRule_ ( `;` _MacroRule_ )\* `;`? +> +> _MacroRule_ :\ +>    _MacroMatcher_ `=>` _MacroTranscriber_ +> +> _MacroMatcher_ :\ +>       `(` _MacroMatch_\* `)`\ +>    | `[` _MacroMatch_\* `]`\ +>    | `{` _MacroMatch_\* `}` +> +> _MacroMatch_ :\ +>       [_Token_]_except $ and delimiters_\ +>    | _MacroMatcher_\ +>    | `$` [IDENTIFIER] `:` _MacroFragSpec_\ +>    | `$` `(` _MacroMatch_+ `)` _MacroRepSep_? _MacroKleeneOp_ +> +> _MacroFragSpec_ :\ +>       `block` | `expr` | `ident` | `item` | `lifetime`\ +>    | `meta` | `pat` | `path` | `stmt` | `tt` | `ty` | `vis` +> +> _MacroRepSep_ :\ +>    [_Token_]_except delimiters and kleene operators_ +> +> _MacroKleeneOp_2015 :\ +>    `*` | `+` +> +> _MacroKleeneOp_2018+ :\ +>    `*` | `+` | `?` +> +> _MacroTranscriber_ :\ +>    [_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 @@ -27,11 +66,11 @@ syntax named by _designator_. Valid designators are: * `expr`: an [expression] * `ty`: a [type] * `ident`: an [identifier] or [keyword] -* `path`: a [path] -* `tt`: a token tree (a single [token] by matching `()`, `[]`, or `{}`) +* `path`: a [_TypePath_] style path +* `tt`: a [token tree] (a single [token] or tokens in matching delimiters `()`, `[]`, or `{}`) * `meta`: the contents of an [attribute] -* `lifetime`: a lifetime. Examples: `'static`, `'a`. -* `vis`: a (visibility qualifier)[visibility-and-privacy] +* `lifetime`: a [lifetime]. Examples: `'static`, `'a`. +* `vis`: a [visibility qualifier] [item]: items.html [block]: expressions/block-expr.html @@ -41,10 +80,12 @@ syntax named by _designator_. Valid designators are: [type]: types.html [identifier]: identifiers.html [keyword]: keywords.html -[path]: paths.html +[_TypePath_]: paths.html#paths-in-types +[token tree]: macros.html#macro-invocation [token]: tokens.html [attribute]: attributes.html -[visibility-and-privacy]: visibility-and-privacy.html +[lifetime]: tokens.html#lifetimes-and-loop-labels +[visibility qualifier]: visibility-and-privacy.html In the transcriber, the designator is already known, and so only the name of a matched nonterminal comes @@ -94,9 +135,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 diff --git a/src/macros.md b/src/macros.md index a68f75ddac9ec..1405944f7e160 100644 --- a/src/macros.md +++ b/src/macros.md @@ -9,6 +9,94 @@ 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 + +> **Syntax**\ +> _MacroInvocation_ :\ +>    [_SimplePath_] `!` _DelimTokenTree_ +> +> _DelimTokenTree_ :\ +>       `(` _TokenTree_\* `)`\ +>    | `[` _TokenTree_\* `]`\ +>    | `{` _TokenTree_\* `}` +> +> _TokenTree_ :\ +>    [_Token_]_except delimiters_ | _DelimTokenTree_ +> +> _MacroInvocationSemi_ :\ +>       [_SimplePath_] `!` `(` _TokenTree_\* `)` `;`\ +>    | [_SimplePath_] `!` `[` _TokenTree_\* `]` `;`\ +>    | [_SimplePath_] `!` `{` _TokenTree_\* `}` + +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 = 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!") }; +} +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 diff --git a/src/patterns.md b/src/patterns.md index d674dea763530..92da4446727d7 100644 --- a/src/patterns.md +++ b/src/patterns.md @@ -12,7 +12,8 @@ >    | [_TuplePattern_]\ >    | [_GroupedPattern_]\ >    | [_SlicePattern_]\ ->    | [_PathPattern_] +>    | [_PathPattern_]\ +>    | [_MacroInvocation_] Patterns are used to match values against structures and to, optionally, bind variables to values inside these structures. They are also @@ -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 diff --git a/src/statements.md b/src/statements.md index c8fa66a1addd0..ab89cbd737d60 100644 --- a/src/statements.md +++ b/src/statements.md @@ -5,7 +5,8 @@ >       `;`\ >    | [_Item_]\ >    | [_LetStatement_]\ ->    | [_ExpressionStatement_] +>    | [_ExpressionStatement_]\ +>    | [_MacroInvocationSemi_] A *statement* is a component of a [block], which is in turn a component of an @@ -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 diff --git a/src/types.md b/src/types.md index fa235c4096734..59203a7261dcd 100644 --- a/src/types.md +++ b/src/types.md @@ -19,7 +19,8 @@ >    | [_SliceType_]\ >    | [_InferredType_]\ >    | [_QualifiedPathInType_]\ ->    | [_BareFunctionType_] +>    | [_BareFunctionType_]\ +>    | [_MacroInvocation_] Every variable, item and value in a Rust program has a type. The _type_ of a *value* defines the interpretation of the memory holding it. @@ -868,6 +869,7 @@ impl Printable for String { [_ImplTraitType_]: #impl-trait [_InferredType_]: #inferred-type [_Lifetime_]: trait-bounds.html +[_MacroInvocation_]: macros.html#macro-invocation [_NeverType_]: #never-type [_ParenthesizedType_]: #parenthesized-types [_QualifiedPathInType_]: paths.html#qualified-paths From 28e1cff84f94d171c10ec2751c7e2da8f13ce0c0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 29 Oct 2018 09:30:52 -0700 Subject: [PATCH 2/3] Update for review comments. --- src/macros-by-example.md | 49 ++++++++++++++++++++-------------------- src/macros.md | 1 + 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/macros-by-example.md b/src/macros-by-example.md index 517102aa68ee4..5e3fa88b59cba 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -59,33 +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] +* `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 [token tree] (a single [token] or tokens in matching delimiters `()`, `[]`, or `{}`) -* `meta`: the contents of an [attribute] -* `lifetime`: a [lifetime]. Examples: `'static`, `'a`. -* `vis`: a [visibility qualifier] - -[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 +* `tt`: a [_TokenTree_] (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 -[token tree]: macros.html#macro-invocation +[_Type_]: types.html +[_Visibility_]: visibility-and-privacy.html [token]: tokens.html -[attribute]: attributes.html -[lifetime]: tokens.html#lifetimes-and-loop-labels -[visibility qualifier]: visibility-and-privacy.html In the transcriber, the designator is already known, and so only the name of a matched nonterminal comes @@ -140,7 +139,7 @@ Rust syntax is restricted in two ways: * `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` + `:`, `>`, `>>`, `[`, `{`, `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 diff --git a/src/macros.md b/src/macros.md index 1405944f7e160..d23ee5f97507f 100644 --- a/src/macros.md +++ b/src/macros.md @@ -82,6 +82,7 @@ trait T { macro_rules! example { () => { println!("Macro call in a macro!") }; } +// Outer macro `example` is expanded, then inner macro `println` is expanded. example!(); ``` From 3e7bb14e3211fb519686413bea5faefd5ec596b3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 3 Nov 2018 11:28:30 -0700 Subject: [PATCH 3/3] Avoid novis footnote in grammar. --- src/items.md | 16 +++++++++++----- src/items/implementations.md | 16 ++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/items.md b/src/items.md index 88e6eaf151c7d..fa1fc2bdbad9b 100644 --- a/src/items.md +++ b/src/items.md @@ -2,7 +2,12 @@ > **Syntax:**\ > _Item_:\ ->    [_OuterAttribute_]\* [_Visibility_]?\ +>    [_OuterAttribute_]\*\ +>       _VisItem_\ +>    | _MacroItem_ +> +> _VisItem_:\ +>    [_Visibility_]?\ >    (\ >          [_Module_]\ >       | [_ExternCrate_]\ @@ -17,9 +22,12 @@ >       | [_Trait_]\ >       | [_Implementation_]\ >       | [_ExternBlock_]\ ->       | [_MacroInvocationSemi_] [^novis]\ ->       | [_MacroRulesDefinition_] [^novis]\ >    ) +> +> _MacroItem_:\ +>       [_MacroInvocationSemi_]\ +>    | [_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; @@ -55,8 +63,6 @@ qualified by the name of the enclosing item, or is private to the enclosing item (in the case of functions). The grammar specifies the exact locations in which sub-item declarations may appear. -[^novis]: Macros may not start with a visibility modifier. - [_ConstantItem_]: items/constant-items.html [_Enumeration_]: items/enumerations.html [_ExternBlock_]: items/external-blocks.html diff --git a/src/items/implementations.md b/src/items/implementations.md index f76686bd45ac1..cab48572a81e6 100644 --- a/src/items/implementations.md +++ b/src/items/implementations.md @@ -11,9 +11,10 @@ >    `}` > > _InherentImplItem_ :\ ->    [_OuterAttribute_]\*\ ->    [_Visibility_]?\ ->    ( [_ConstantItem_] | [_Function_] | [_Method_] | [_MacroInvocationSemi_] [^novis] ) +>    [_OuterAttribute_]\* (\ +>          [_MacroInvocationSemi_]\ +>       | ( [_Visibility_]? ( [_ConstantItem_] | [_Function_] | [_Method_] ) )\ +>    ) > > _TraitImpl_ :\ >    `unsafe`? `impl` [_Generics_] `!`? @@ -25,9 +26,10 @@ >    `}` > > _TraitImplItem_ :\ ->    [_OuterAttribute_]\*\ ->    [_Visibility_]?\ ->    ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] | [_Method_] | [_MacroInvocationSemi_] [^novis] ) +>    [_OuterAttribute_]\* (\ +>          [_MacroInvocationSemi_]\ +>       | ( [_Visibility_]? ( [_TypeAlias_] | [_ConstantItem_] | [_Function_] | [_Method_] ) )\ +>    ) An _implementation_ is an item that associates items with an _implementing type_. Implementations are defined with the keyword `impl` and contain functions @@ -175,8 +177,6 @@ attributes must come before any associated items. That attributes that have meaning here are [`cfg`], [`deprecated`], [`doc`], and [the lint check attributes]. -[^novis]: Macro invocations may not start with a visibility modifier. - [IDENTIFIER]: identifiers.html [_ConstantItem_]: items/constant-items.html [_Function_]: items/functions.html