# parser in syn::meta - Rust
Make a parser that is usable with `parse_macro_input!` in a `#[proc_macro_attribute]` macro.

syn::meta

# Function parser

Source

    pub fn parser(
        logic: impl FnMut(ParseNestedMeta<'_>) -> Result<()>,
    ) -> impl Parser<Output = ()>

Expand description

Make a parser that is usable with `parse_macro_input!` in a `#[proc_macro_attribute]` macro.

Warning: When parsing attribute args other than the `proc_macro::TokenStream` input of a `proc_macro_attribute`, you do not need this function. In several cases your callers will get worse error messages if you use this function, because the surrounding delimiter’s span is concealed from attribute macros by rustc. Use `Attribute::parse_nested_meta` instead.

## §Example

This example implements an attribute macro whose invocations look like this:

    #[tea(kind = "EarlGrey", hot)]
    struct Picard {...}

The “parameters” supported by the attribute are:

- `kind = "..."`
- `hot`
- `with(sugar, milk, ...)`, a comma-separated list of ingredients

    use proc_macro::TokenStream;
    use syn::{parse_macro_input, LitStr, Path};

    #[proc_macro_attribute]
    pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream {
        let mut kind: Option<LitStr> = None;
        let mut hot: bool = false;
        let mut with: Vec<Path> = Vec::new();
        let tea_parser = syn::meta::parser(|meta| {
            if meta.path.is_ident("kind") {
                kind = Some(meta.value()?.parse()?);
                Ok(())
            } else if meta.path.is_ident("hot") {
                hot = true;
                Ok(())
            } else if meta.path.is_ident("with") {
                meta.parse_nested_meta(|meta| {
                    with.push(meta.path);
                    Ok(())
                })
            } else {
                Err(meta.error("unsupported tea property"))
            }
        });

        parse_macro_input!(args with tea_parser);
        eprintln!("kind={kind:?} hot={hot} with={with:?}");

        /* ... */
    }

The `syn::meta` library will take care of dealing with the commas including trailing commas, and producing sensible error messages on unexpected input.

    error: expected `,`
     --> src/main.rs:3:37
      |
    3 | #[tea(kind = "EarlGrey", with(sugar = "lol", milk))]
      |                                     ^

## §Example

Same as above but we factor out most of the logic into a separate function.

    use proc_macro::TokenStream;
    use syn::meta::ParseNestedMeta;
    use syn::parse::{Parser, Result};
    use syn::{parse_macro_input, LitStr, Path};

    #[proc_macro_attribute]
    pub fn tea(args: TokenStream, input: TokenStream) -> TokenStream {
        let mut attrs = TeaAttributes::default();
        let tea_parser = syn::meta::parser(|meta| attrs.parse(meta));
        parse_macro_input!(args with tea_parser);

        /* ... */
    }

    #[derive(Default)]
    struct TeaAttributes {
        kind: Option<LitStr>,
        hot: bool,
        with: Vec<Path>,
    }

    impl TeaAttributes {
        fn parse(&mut self, meta: ParseNestedMeta) -> Result<()> {
            if meta.path.is_ident("kind") {
                self.kind = Some(meta.value()?.parse()?);
                Ok(())
            } else /* just like in last example */

        }
    }