1 use super::*;
2 use crate::token::{Brace, Bracket, Paren};
3 use proc_macro2::TokenStream;
4 #[cfg(feature = "parsing")]
5 use proc_macro2::{Delimiter, Group, Span, TokenTree};
6 
7 #[cfg(feature = "parsing")]
8 use crate::parse::{Parse, ParseStream, Parser, Result};
9 #[cfg(feature = "extra-traits")]
10 use crate::tt::TokenStreamHelper;
11 #[cfg(feature = "extra-traits")]
12 use std::hash::{Hash, Hasher};
13 
14 ast_struct! {
15     /// A macro invocation: `println!("{}", mac)`.
16     ///
17     /// *This type is available only if Syn is built with the `"derive"` or `"full"`
18     /// feature.*
19     pub struct Macro #manual_extra_traits {
20         pub path: Path,
21         pub bang_token: Token![!],
22         pub delimiter: MacroDelimiter,
23         pub tokens: TokenStream,
24     }
25 }
26 
27 ast_enum! {
28     /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
29     ///
30     /// *This type is available only if Syn is built with the `"derive"` or `"full"`
31     /// feature.*
32     pub enum MacroDelimiter {
33         Paren(Paren),
34         Brace(Brace),
35         Bracket(Bracket),
36     }
37 }
38 
39 #[cfg(feature = "extra-traits")]
40 impl Eq for Macro {}
41 
42 #[cfg(feature = "extra-traits")]
43 impl PartialEq for Macro {
eq(&self, other: &Self) -> bool44     fn eq(&self, other: &Self) -> bool {
45         self.path == other.path
46             && self.bang_token == other.bang_token
47             && self.delimiter == other.delimiter
48             && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
49     }
50 }
51 
52 #[cfg(feature = "extra-traits")]
53 impl Hash for Macro {
hash<H>(&self, state: &mut H) where H: Hasher,54     fn hash<H>(&self, state: &mut H)
55     where
56         H: Hasher,
57     {
58         self.path.hash(state);
59         self.bang_token.hash(state);
60         self.delimiter.hash(state);
61         TokenStreamHelper(&self.tokens).hash(state);
62     }
63 }
64 
65 #[cfg(feature = "parsing")]
delimiter_span_close(macro_delimiter: &MacroDelimiter) -> Span66 fn delimiter_span_close(macro_delimiter: &MacroDelimiter) -> Span {
67     let delimiter = match macro_delimiter {
68         MacroDelimiter::Paren(_) => Delimiter::Parenthesis,
69         MacroDelimiter::Brace(_) => Delimiter::Brace,
70         MacroDelimiter::Bracket(_) => Delimiter::Bracket,
71     };
72     let mut group = Group::new(delimiter, TokenStream::new());
73     group.set_span(match macro_delimiter {
74         MacroDelimiter::Paren(token) => token.span,
75         MacroDelimiter::Brace(token) => token.span,
76         MacroDelimiter::Bracket(token) => token.span,
77     });
78     group.span_close()
79 }
80 
81 impl Macro {
82     /// Parse the tokens within the macro invocation's delimiters into a syntax
83     /// tree.
84     ///
85     /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it
86     /// produces a more useful span when `tokens` is empty.
87     ///
88     /// # Example
89     ///
90     /// ```
91     /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token};
92     /// use syn::ext::IdentExt;
93     /// use syn::parse::{Error, Parse, ParseStream, Result};
94     /// use syn::punctuated::Punctuated;
95     ///
96     /// // The arguments expected by libcore's format_args macro, and as a
97     /// // result most other formatting and printing macros like println.
98     /// //
99     /// //     println!("{} is {number:.prec$}", "x", prec=5, number=0.01)
100     /// struct FormatArgs {
101     ///     format_string: Expr,
102     ///     positional_args: Vec<Expr>,
103     ///     named_args: Vec<(Ident, Expr)>,
104     /// }
105     ///
106     /// impl Parse for FormatArgs {
107     ///     fn parse(input: ParseStream) -> Result<Self> {
108     ///         let format_string: Expr;
109     ///         let mut positional_args = Vec::new();
110     ///         let mut named_args = Vec::new();
111     ///
112     ///         format_string = input.parse()?;
113     ///         while !input.is_empty() {
114     ///             input.parse::<Token![,]>()?;
115     ///             if input.is_empty() {
116     ///                 break;
117     ///             }
118     ///             if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
119     ///                 while !input.is_empty() {
120     ///                     let name: Ident = input.call(Ident::parse_any)?;
121     ///                     input.parse::<Token![=]>()?;
122     ///                     let value: Expr = input.parse()?;
123     ///                     named_args.push((name, value));
124     ///                     if input.is_empty() {
125     ///                         break;
126     ///                     }
127     ///                     input.parse::<Token![,]>()?;
128     ///                 }
129     ///                 break;
130     ///             }
131     ///             positional_args.push(input.parse()?);
132     ///         }
133     ///
134     ///         Ok(FormatArgs {
135     ///             format_string,
136     ///             positional_args,
137     ///             named_args,
138     ///         })
139     ///     }
140     /// }
141     ///
142     /// // Extract the first argument, the format string literal, from an
143     /// // invocation of a formatting or printing macro.
144     /// fn get_format_string(m: &Macro) -> Result<LitStr> {
145     ///     let args: FormatArgs = m.parse_body()?;
146     ///     match args.format_string {
147     ///         Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit),
148     ///         other => {
149     ///             // First argument was not a string literal expression.
150     ///             // Maybe something like: println!(concat!(...), ...)
151     ///             Err(Error::new_spanned(other, "format string must be a string literal"))
152     ///         }
153     ///     }
154     /// }
155     ///
156     /// fn main() {
157     ///     let invocation = parse_quote! {
158     ///         println!("{:?}", Instant::now())
159     ///     };
160     ///     let lit = get_format_string(&invocation).unwrap();
161     ///     assert_eq!(lit.value(), "{:?}");
162     /// }
163     /// ```
164     #[cfg(feature = "parsing")]
parse_body<T: Parse>(&self) -> Result<T>165     pub fn parse_body<T: Parse>(&self) -> Result<T> {
166         self.parse_body_with(T::parse)
167     }
168 
169     /// Parse the tokens within the macro invocation's delimiters using the
170     /// given parser.
171     #[cfg(feature = "parsing")]
parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output>172     pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
173         let scope = delimiter_span_close(&self.delimiter);
174         crate::parse::parse_scoped(parser, scope, self.tokens.clone())
175     }
176 }
177 
178 #[cfg(feature = "parsing")]
parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)>179 pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
180     input.step(|cursor| {
181         if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
182             let span = g.span();
183             let delimiter = match g.delimiter() {
184                 Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
185                 Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
186                 Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
187                 Delimiter::None => {
188                     return Err(cursor.error("expected delimiter"));
189                 }
190             };
191             Ok(((delimiter, g.stream()), rest))
192         } else {
193             Err(cursor.error("expected delimiter"))
194         }
195     })
196 }
197 
198 #[cfg(feature = "parsing")]
199 pub mod parsing {
200     use super::*;
201 
202     use crate::parse::{Parse, ParseStream, Result};
203 
204     impl Parse for Macro {
parse(input: ParseStream) -> Result<Self>205         fn parse(input: ParseStream) -> Result<Self> {
206             let tokens;
207             Ok(Macro {
208                 path: input.call(Path::parse_mod_style)?,
209                 bang_token: input.parse()?,
210                 delimiter: {
211                     let (delimiter, content) = parse_delimiter(input)?;
212                     tokens = content;
213                     delimiter
214                 },
215                 tokens,
216             })
217         }
218     }
219 }
220 
221 #[cfg(feature = "printing")]
222 mod printing {
223     use super::*;
224     use proc_macro2::TokenStream;
225     use quote::ToTokens;
226 
227     impl ToTokens for Macro {
to_tokens(&self, tokens: &mut TokenStream)228         fn to_tokens(&self, tokens: &mut TokenStream) {
229             self.path.to_tokens(tokens);
230             self.bang_token.to_tokens(tokens);
231             match &self.delimiter {
232                 MacroDelimiter::Paren(paren) => {
233                     paren.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
234                 }
235                 MacroDelimiter::Brace(brace) => {
236                     brace.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
237                 }
238                 MacroDelimiter::Bracket(bracket) => {
239                     bracket.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
240                 }
241             }
242         }
243     }
244 }
245