syn_pub_items/
parse_macro_input.rs

1/// Parse the input TokenStream of a macro, triggering a compile error if the
2/// tokens fail to parse.
3///
4/// Refer to the [`parse` module] documentation for more details about parsing
5/// in Syn.
6///
7/// [`parse` module]: parse/index.html
8///
9/// # Intended usage
10///
11/// ```edition2018
12/// extern crate proc_macro;
13///
14/// use proc_macro::TokenStream;
15/// use syn::{parse_macro_input, Result};
16/// use syn::parse::{Parse, ParseStream};
17///
18/// struct MyMacroInput {
19///     /* ... */
20/// }
21///
22/// impl Parse for MyMacroInput {
23///     fn parse(input: ParseStream) -> Result<Self> {
24///         /* ... */
25/// #       Ok(MyMacroInput {})
26///     }
27/// }
28///
29/// # const IGNORE: &str = stringify! {
30/// #[proc_macro]
31/// # };
32/// pub fn my_macro(tokens: TokenStream) -> TokenStream {
33///     let input = parse_macro_input!(tokens as MyMacroInput);
34///
35///     /* ... */
36/// #   "".parse().unwrap()
37/// }
38/// ```
39#[macro_export(local_inner_macros)]
40macro_rules! parse_macro_input {
41    ($tokenstream:ident as $ty:ty) => {
42        match $crate::parse_macro_input::parse::<$ty>($tokenstream) {
43            $crate::export::Ok(data) => data,
44            $crate::export::Err(err) => {
45                return $crate::export::TokenStream::from(err.to_compile_error());
46            }
47        }
48    };
49    ($tokenstream:ident) => {
50        parse_macro_input!($tokenstream as _)
51    };
52}
53
54////////////////////////////////////////////////////////////////////////////////
55// Can parse any type that implements Parse.
56
57use parse::{Parse, ParseStream, Parser, Result};
58use proc_macro::TokenStream;
59
60// Not public API.
61#[doc(hidden)]
62pub fn parse<T: ParseMacroInput>(token_stream: TokenStream) -> Result<T> {
63    T::parse.parse(token_stream)
64}
65
66// Not public API.
67#[doc(hidden)]
68pub trait ParseMacroInput: Sized {
69    fn parse(input: ParseStream) -> Result<Self>;
70}
71
72impl<T: Parse> ParseMacroInput for T {
73    fn parse(input: ParseStream) -> Result<Self> {
74        <T as Parse>::parse(input)
75    }
76}
77
78////////////////////////////////////////////////////////////////////////////////
79// Any other types that we want `parse_macro_input!` to be able to parse.
80
81#[cfg(any(feature = "full", feature = "derive"))]
82use AttributeArgs;
83
84#[cfg(any(feature = "full", feature = "derive"))]
85impl ParseMacroInput for AttributeArgs {
86    fn parse(input: ParseStream) -> Result<Self> {
87        let mut metas = Vec::new();
88
89        loop {
90            if input.is_empty() {
91                break;
92            }
93            let value = input.parse()?;
94            metas.push(value);
95            if input.is_empty() {
96                break;
97            }
98            input.parse::<Token![,]>()?;
99        }
100
101        Ok(metas)
102    }
103}