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}