Skip to content
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

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 37 additions & 18 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Copy link
Contributor

@LeoTestard LeoTestard Jun 1, 2016

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.


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.)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should explicit the term ‶transcriber″. :)

Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do footnotes work in rustdoc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Contributor

@LeoTestard LeoTestard Jun 1, 2016

Choose a reason for hiding this comment

The 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.

Expand All @@ -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)
Expand All @@ -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
Copy link
Contributor

@LeoTestard LeoTestard Jun 1, 2016

Choose a reason for hiding this comment

The 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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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
Expand Down