[][src]Crate defile

::defile

Helper 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 invsibile parenthesis.

Example

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 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::item! {
      fn main () {
          $(
              println!("vvvvvvvvvvvvv");
              check_expr!(@$expr); // put `@` before a metavariable to ungroup it
              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.

Caveats

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.

Macros

expr

Macro to be used to expand to an expression.

item

Macro to be used to expand to an item definition.