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