Fragment Specifiers

As shown in the macro_rules chapter, Rust, as of 1.53, has 13 fragment specifiers. This section will go a bit more into detail for some of them and shows a few example inputs of what each matcher matches.

Note: Capturing with anything but the ident, lifetime and tt fragments will render the captured AST opaque, making it impossible to further match it with other fragment specifiers in future macro invocations.

block

The block fragment solely matches a block expression, which consists of an opening { brace, followed by any number of statements and finally followed by a closing } brace.

macro_rules! blocks {
    ($($block:block)*) => ();
}

blocks! {
    {}
    {
        let zig;
    }
    { 2 }
}
fn main() {}

expr

The expr fragment matches any kind of expression(Rust has a lot of them, given it is an expression orientated language).

macro_rules! expressions {
    ($($expr:expr)*) => ();
}

expressions! {
    "literal"
    funcall()
    future.await
    break 'foo bar
}
fn main() {}

ident

The ident fragment matches an identifier or keyword.

macro_rules! idents {
    ($($ident:ident)*) => ();
}

idents! {
    // _ <- This is not an ident, it is a pattern
    foo
    async
    O_________O
    _____O_____
}
fn main() {}

item

The item fragment simply matches any of Rust's item definitions, not identifiers that refer to items. This includes visibility modifiers.

macro_rules! items {
    ($($item:item)*) => ();
}

items! {
    struct Foo;
    enum Bar {
        Baz
    }
    impl Foo {}
    pub use crate::foo;
    /*...*/
}
fn main() {}

lifetime

The lifetime fragment matches a lifetime or label. It's quite similar to ident but with a prepended '.

macro_rules! lifetimes {
    ($($lifetime:lifetime)*) => ();
}

lifetimes! {
    'static
    'shiv
    '_
}
fn main() {}

literal

The literal fragment matches any literal expression.

macro_rules! literals {
    ($($literal:literal)*) => ();
}

literals! {
    -1
    "hello world"
    2.3
    b'b'
    true
}
fn main() {}

meta

The meta fragment matches an attribute, to be more precise, the contents of an attribute. That is, it will match a simple path, one without generic arguments followed by a delimited token tree or an = followed by a literal expression.

Note: You will usually see this fragment being used in a matcher like #[$meta:meta] or #![$meta:meta] to actually capture an attribute.

macro_rules! metas {
    ($($meta:meta)*) => ();
}

metas! {
    ASimplePath
    super::man
    path = "home"
    foo(bar)
}
fn main() {}

Doc-Comment Fact: Doc-Comments like /// ... and !// ... are actually syntax sugar for attributes! They desugar to #[doc="..."] and #![doc="..."] respectively, meaning you can match on them like with attributes!

pat

The pat fragment matches any kind of pattern, except or-patterns.

macro_rules! patterns {
    ($($pat:pat)*) => ();
}

patterns! {
    "literal"
    _
    0..5
    ref mut PatternsAreNice
}
fn main() {}

path

The path fragment matches a so called TypePath style path. This includes the function style trait forms, Fn() -> ().

macro_rules! paths {
    ($($path:path)*) => ();
}

paths! {
    ASimplePath
    ::A::B::C::D
    G::<eneri>::C
    FnMut(u32) -> ()
}
fn main() {}

stmt

The statement fragment solely matches a statement without its trailing semicolon, unless its an item statement that requires one.

What would be an item statement that requires one? A Unit-Struct would be a simple one, as defining one requires a trailing semicolon.

Let's use a simple example to show exactly what is meant with this. We use a macro that merely emits what it captures:

macro_rules! statements {
    ($($stmt:stmt)*) => ($($stmt)*);
}

fn main() {
    statements! {
        struct Foo;
        fn foo() {}
        let zig = 3
        let zig = 3;
        3
        3;
        if true {} else {}
        {}
    }
}

Expanding this, via the playground for example1, gives us roughly the following:

/* snip */

fn main() {
    struct Foo;
    fn foo() { }
    let zig = 3;
    let zig = 3;
    ;
    3;
    3;
    ;
    if true { } else { }
    { }
}

From this we can tell a few things:

The first you should be able to see immediately is that while the stmt fragment doesn't capture trailing semicolons, it still emits them when required, even if the statement is already followed by one. The simple reason for that is that semicolons on their own are already valid statements which the fragment captures eagerly. So our macro isn't capturing 8 times, but 11! This can be important when doing multiples repetitions and expanding these in one repetition expansion, as the repetition numbers have to match in those cases.

Another thing you should be able to notice here is that the trailing semicolon of the struct Foo; item statement is being matched, otherwise we would've seen an extra one like in the other cases. This makes sense as we already said, that for item statements that require one, the trailing semicolon will be matched with.

A last observation is that expressions get emitted back with a trailing semicolon, unless the expression solely consists of only a block expression or control flow expression.

The fine details of what was just mentioned here can be looked up in the reference.

Fortunately, these fine details here are usually not of importance whatsoever, with the small exception that was mentioned earlier in regards to repetitions which by itself shouldn't be a common problem to run into.

1

See the debugging chapter for tips on how to do this.

tt

The tt fragment matches a TokenTree. If you need a refresher on what exactly a TokenTree was you may want to revisit the TokenTree chapter of this book. The tt fragment is one of the most powerful fragments, as it can match nearly anything while still allowing you to inspect the contents of it at a later state in the macro.

This allows one to make use of very powerful patterns like the tt-muncher or the push-down-accumulator.

ty

The ty fragment matches any kind of type expression.

macro_rules! types {
    ($($type:ty)*) => ();
}

types! {
    foo::bar
    bool
    [u8]
    impl IntoIterator<Item = u32>
}
fn main() {}

vis

The vis fragment matches a possibly empty Visibility qualifier. Emphasis lies on the possibly empty part. You can kind of think of this fragment as having an implicit ? repetition to it, meaning you don't, and in fact cannot, wrap it in a direct repetition, though this only applies for matching. When expanding this fragment you expand it without a $(...)? repetition block.

macro_rules! visibilities {
    //         ∨~~Note this comma, since we cannot repeat a `vis` fragment on its own
    ($($vis:vis,)*) => ();
}

visibilities! {
    , // no vis is fine, as its implicitly
    pub,
    pub(crate),
    pub(in super),
    pub(in some_path),
}
fn main() {}