-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[wip] reference: rework Macros section #31990
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -555,17 +555,33 @@ Users of `rustc` can define new syntax extensions in two ways: | |
|
||
## Macros | ||
|
||
`macro_rules` allows users to define syntax extension in a declarative way. We | ||
call such extensions "macros by example" or simply "macros" — to be distinguished | ||
from the "procedural macros" defined in [compiler plugins][plugin]. | ||
`macro_rules` allows users to define syntax extensions in a declarative way. | ||
We call such extensions "`macro_rules!` macros" or simply "macros" — to be | ||
distinguished from the "procedural macros" defined in [compiler plugins][plugin]. | ||
|
||
Currently, macros can expand to expressions, statements, items, or patterns. | ||
As shown below, the body of a `macro_rules` macro consists of one or more | ||
semicolon-separated arms, similar in appearance to a `match` statement. On | ||
the left side of the `=>` is a matcher describing the syntax that the macro | ||
accepts, optionally capturing parts of it for use in the transcriber, which | ||
is on the right side of the `=>`. (Choice of delimiters for the macro body, | ||
matchers, and transcribers is arbitrary.) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should explicit the term ‶transcriber″. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choice is arbitrary, but delimiters are mandatory. You might want to add that. |
||
|
||
(A `sep_token` is any token other than `*` and `+`. A `non_special_token` is | ||
any token other than a delimiter or `$`.) | ||
```rust,ignore | ||
macro_rules! /* name of macro */ { | ||
(/* matcher for arm 1 */) => { /* transcriber for arm 1 */ }; | ||
(/* matcher for arm 2 */) => { /* transcriber for arm 2 */ } | ||
} | ||
``` | ||
|
||
The macro expander looks up macro invocations by name, and tries each macro | ||
rule in turn. It transcribes the first successful match. Matching and | ||
Currently, macros can expand to expressions, statements, items, patterns, or | ||
types[^typemacros]. This distinction is inferred from the context in which the | ||
macro is invoked, and carefully written macros may work in multiple contexts. | ||
|
||
[^typemacros]: Gated by | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do footnotes work in rustdoc? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same syntax is used elsewhere in the reference. |
||
[the `type_macros` feature](https://github.com/rust-lang/rust/issues/27245). | ||
|
||
The macro expander looks up macro invocations by name, and tries each | ||
arm in turn. It transcribes the first successful match. Matching and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it should once #33840 lands at least. |
||
transcription are closely related to each other, and we will describe them | ||
together. | ||
|
||
|
@@ -576,7 +592,8 @@ a `$` literally, including delimiters. For parsing reasons, delimiters must be | |
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: | ||
syntax named by _designator_ (also called a _fragment specifier_). Valid | ||
designators are: | ||
|
||
* `item`: an [item](#items) | ||
* `block`: a [block](#block-expressions) | ||
|
@@ -586,17 +603,17 @@ syntax named by _designator_. Valid designators are: | |
* `ty`: a [type](#types) | ||
* `ident`: an [identifier](#identifiers) | ||
* `path`: a [path](#paths) | ||
* `tt`: either side of the `=>` in macro rules | ||
* `tt`: a "token tree": either one [token](#token) or a delimited sequence | ||
of token trees | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might want to add a compareason with LISP or an AST to explain more precisely what a token tree is. But it would maybe become a bit heavy. |
||
* `meta`: the contents of an [attribute](#attributes) | ||
|
||
In the transcriber, the | ||
designator is already known, and so only the name of a matched nonterminal comes | ||
after the dollar sign. | ||
In the transcriber, the designator is already known, and so only the name of a matched | ||
nonterminal comes after the dollar sign. | ||
|
||
In both the matcher and transcriber, the Kleene star-like operator indicates | ||
In both the matcher and transcriber, the Kleene star operator indicates | ||
repetition. The Kleene star operator consists of `$` and parentheses, optionally | ||
followed by a separator token, followed by `*` or `+`. `*` means zero or more | ||
repetitions, `+` means at least one repetition. The parentheses are not matched or | ||
repetitions; `+` means at least one repetition. The parentheses are not matched or | ||
transcribed. On the matcher side, a name is bound to _all_ of the names it | ||
matches, in a structure that mimics the structure of the repetition encountered | ||
on a successful match. The job of the transcriber is to sort that structure | ||
|
@@ -605,8 +622,8 @@ out. | |
The rules for transcription of these repetitions are called "Macro By Example". | ||
Essentially, one "layer" of repetition is discharged at a time, and all of them | ||
must be discharged by the time a name is transcribed. Therefore, `( $( $i:ident | ||
),* ) => ( $i )` is an invalid macro, but `( $( $i:ident ),* ) => ( $( $i:ident | ||
),* )` is acceptable (if trivial). | ||
),* ) => ( $i )` is an invalid macro, but `( $( $i:ident ),* ) => ( $( $i ),* )` | ||
is acceptable (though trivial). | ||
|
||
When Macro By Example encounters a repetition, it examines all of the `$` | ||
_name_ s that occur in its body. At the "current layer", they all must repeat | ||
|
@@ -615,7 +632,7 @@ the same number of times, so ` ( $( $i:ident ),* ; $( $j:ident ),* ) => ( $( | |
`(a,b,c ; d,e)`. The repetition walks through the choices at that layer in | ||
lockstep, so the former input transcribes to `(a,d), (b,e), (c,f)`. | ||
|
||
Nested repetitions are allowed. | ||
Nested repetitions are allowed. In the transcriber, `*` vs `+` does not matter. | ||
|
||
### Parsing limitations | ||
|
||
|
@@ -634,6 +651,8 @@ Rust syntax is restricted in two ways: | |
|
||
[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md | ||
|
||
### Scoping | ||
|
||
# Crates and source files | ||
|
||
Although Rust, like any other language, can be implemented by an interpreter as | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The term ‶macros by example″ has also been used at several places and might be worth mentionning.