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