syn_pub_items/
mac.rs

1use super::*;
2use proc_macro2::TokenStream;
3#[cfg(feature = "parsing")]
4use proc_macro2::{Delimiter, TokenTree};
5use token::{Brace, Bracket, Paren};
6
7#[cfg(feature = "parsing")]
8use parse::{ParseStream, Result};
9#[cfg(feature = "extra-traits")]
10use std::hash::{Hash, Hasher};
11#[cfg(feature = "extra-traits")]
12use tt::TokenStreamHelper;
13
14ast_struct! {
15    /// A macro invocation: `println!("{}", mac)`.
16    ///
17    /// *This type is available 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 tts: TokenStream,
24    }
25}
26
27ast_enum! {
28    /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
29    ///
30    /// *This type is available 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")]
40impl Eq for Macro {}
41
42#[cfg(feature = "extra-traits")]
43impl PartialEq for Macro {
44    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.tts) == TokenStreamHelper(&other.tts)
49    }
50}
51
52#[cfg(feature = "extra-traits")]
53impl Hash for Macro {
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.tts).hash(state);
62    }
63}
64
65#[cfg(feature = "parsing")]
66pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
67    input.step(|cursor| {
68        if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
69            let span = g.span();
70            let delimiter = match g.delimiter() {
71                Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
72                Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
73                Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
74                Delimiter::None => {
75                    return Err(cursor.error("expected delimiter"));
76                }
77            };
78            Ok(((delimiter, g.stream().clone()), rest))
79        } else {
80            Err(cursor.error("expected delimiter"))
81        }
82    })
83}
84
85#[cfg(feature = "parsing")]
86pub mod parsing {
87    use super::*;
88
89    use parse::{Parse, ParseStream, Result};
90
91    impl Parse for Macro {
92        fn parse(input: ParseStream) -> Result<Self> {
93            let tts;
94            Ok(Macro {
95                path: input.call(Path::parse_mod_style)?,
96                bang_token: input.parse()?,
97                delimiter: {
98                    let (delimiter, content) = parse_delimiter(input)?;
99                    tts = content;
100                    delimiter
101                },
102                tts: tts,
103            })
104        }
105    }
106}
107
108#[cfg(feature = "printing")]
109mod printing {
110    use super::*;
111    use proc_macro2::TokenStream;
112    use quote::ToTokens;
113
114    impl ToTokens for Macro {
115        fn to_tokens(&self, tokens: &mut TokenStream) {
116            self.path.to_tokens(tokens);
117            self.bang_token.to_tokens(tokens);
118            match self.delimiter {
119                MacroDelimiter::Paren(ref paren) => {
120                    paren.surround(tokens, |tokens| self.tts.to_tokens(tokens));
121                }
122                MacroDelimiter::Brace(ref brace) => {
123                    brace.surround(tokens, |tokens| self.tts.to_tokens(tokens));
124                }
125                MacroDelimiter::Bracket(ref bracket) => {
126                    bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens));
127                }
128            }
129        }
130    }
131}