| Crates.io | defile |
| lib.rs | defile |
| version | 0.2.1 |
| created_at | 2020-07-04 20:20:01.62012+00 |
| updated_at | 2023-07-19 17:22:32.191836+00 |
| description | Proc-macro helper to ungroup macro metavariables |
| homepage | https://crates.io/crates/defile |
| repository | https://github.com/danielhenrymantilla/rust-defile |
| max_upload_size | |
| id | 261414 |
| size | 28,700 |
::defileHelper proc-macro to "ungroup" a captured metavariable (thus potentially breaking their hygiene, hence the name).
This is useful when using helper macro_rules macros, that need to parse using some special rule (e.g. :expr, :path, :pat), but that later want to further inspect the captured variable.
This is not something a macro_rules! can do on its own, since such so-called metavariables are seen as an opaque single token (:tt) (the sequence of tokens captured in the metavariable have been grouped (≈ parenthesized) but using invisible parenthesis.
macro_rules! check_expr {
(
42
) => ({
println!("Got `42`!");
});
(
$($tt:tt)*
) => ({
println!("Did not get `42`. Instead, got the following tokens:\n[");
$(
println!(" `{}`,", stringify!($tt));
)*
println!("]");
});
}
macro_rules! check_all_exprs {(
$(
$expr:expr // use :expr to be able to use `,` as a delimiter
),* $(,)?
) => (
fn main () {
$(
println!("vvvvvvvvvvvvv");
check_expr!($expr);
println!("^^^^^^^^^^^^^\n");
)*
}
)}
check_all_exprs!(42, 1 + 1);
outputs:
vvvvvvvvvvvvv
Did not get `42`. Instead, got the following tokens:
[
`42`,
]
^^^^^^^^^^^^^
vvvvvvvvvvvvv
Did not get `42`. Instead, got the following tokens:
[
`1 + 1`,
]
^^^^^^^^^^^^^
That is:
The token 42 does not match 42!
That being said, the expression 1 + 1 is viewed as a single indivisible
token too.
Indeed, that's kind of the point of this behavior: if we do 2 * $expr
where $expr captures 1 + 1 we expect the result to be 2 * (1 + 1)
instead of 2 * 1 + 1!
But by doing:
macro_rules! check_all_exprs {(
$(
$expr:expr // use :expr to be able to use `,` as a delimiter
),* $(,)?
) => (::defile::defile! { // 👈
fn main () {
$(
println!("vvvvvvvvvvvvv");
check_expr!(@$expr);
// 👆
println!("^^^^^^^^^^^^^\n");
)*
}
})}
we do get:
vvvvvvvvvvvvv
Got `42`!
^^^^^^^^^^^^^
vvvvvvvvvvvvv
Did not get `42`. Instead, got the following tokens:
[
`1`,
`+`,
`1`,
]
^^^^^^^^^^^^^
42 has matched the literal 42, but be aware that this has also resulted
in 1 + 1 getting split. So, if you were to defile expressions such as
2 * @$expr, you may not obtain the expected result! Use with caution.Currently (1.45.0), there are several bugs regarding the interaction between
macro_rules! macros and procedural macros, that may lead to defile! and any
other helper procedural macro to split groups that are not @-prefixed.
Hopefully those bugs are solved, making the actual implementation of defile!
meaningful.