Reputation: 3067
I am trying to match a struct
in a Rust macro. I need to pull the
struct
apart somewhat to get its name. I figured that the block
matcher would do the trick. Consider, for example this:
macro_rules! multi {
(struct $name:ident $block:block) => {
enum George {$name}
}
}
multi!{
struct Fred {
a:String
}
}
which expands to
enum George { Fred, }
which is about right.
However, if I turn this back into a struct
, it fails.
macro_rules! multi {
(struct $name:ident $block:block) => {
struct $name $block
}
}
which gives this error.
error: expected `where`, `{`, `(`, or `;` after struct name, found `{ a: String }`
--> src/main.rs:64:22
|
64 | struct $name $block
| ^^^^^^ expected `where`, `{`, `(`, or `;` after struct name
It looks like {a: String}
is being treated as a single token, rather
than being re-parsed; but it is what should be going in there.
Upvotes: 2
Views: 2358
Reputation: 11043
The $:block
matcher is for block expressions, i.e. a set of curly braces containing zero or more Rust statements and items and an optional trailing return value. For example the following are blocks:
{
let x = 1;
}
{
#[derive(Default)]
struct S;
S::default()
}
Examples of curly braces in Rust that are blocks are:
if
and else
clauses,for
, while
, and loop
loops.The curly braces around the fields of a struct are not a block because they are not supposed to contain zero or more Rust statements and items followed by an optional trailing return value. Instead they are supposed to contain the names and types of the struct fields.
In a macro you can match an arbitrary set of curly braces using the pattern { $($tt:tt)* }
, which means "curly braces containing any number of arbitrary tokens."
macro_rules! multi {
(struct $name:ident { $($tt:tt)* }) => {
struct $name { $($tt)* }
};
}
multi! {
struct Fred {
a: String,
}
}
Upvotes: 5