| use super::*; |
| use proc_macro2::TokenStream; |
| #[cfg(feature = "parsing")] |
| use proc_macro2::{Delimiter, TokenTree}; |
| use token::{Brace, Bracket, Paren}; |
| |
| #[cfg(feature = "parsing")] |
| use parse::{ParseStream, Result}; |
| #[cfg(feature = "extra-traits")] |
| use std::hash::{Hash, Hasher}; |
| #[cfg(feature = "extra-traits")] |
| use tt::TokenStreamHelper; |
| |
| ast_struct! { |
| /// A macro invocation: `println!("{}", mac)`. |
| /// |
| /// *This type is available if Syn is built with the `"derive"` or `"full"` |
| /// feature.* |
| pub struct Macro #manual_extra_traits { |
| pub path: Path, |
| pub bang_token: Token![!], |
| pub delimiter: MacroDelimiter, |
| pub tts: TokenStream, |
| } |
| } |
| |
| ast_enum! { |
| /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`. |
| /// |
| /// *This type is available if Syn is built with the `"derive"` or `"full"` |
| /// feature.* |
| pub enum MacroDelimiter { |
| Paren(Paren), |
| Brace(Brace), |
| Bracket(Bracket), |
| } |
| } |
| |
| #[cfg(feature = "extra-traits")] |
| impl Eq for Macro {} |
| |
| #[cfg(feature = "extra-traits")] |
| impl PartialEq for Macro { |
| fn eq(&self, other: &Self) -> bool { |
| self.path == other.path |
| && self.bang_token == other.bang_token |
| && self.delimiter == other.delimiter |
| && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) |
| } |
| } |
| |
| #[cfg(feature = "extra-traits")] |
| impl Hash for Macro { |
| fn hash<H>(&self, state: &mut H) |
| where |
| H: Hasher, |
| { |
| self.path.hash(state); |
| self.bang_token.hash(state); |
| self.delimiter.hash(state); |
| TokenStreamHelper(&self.tts).hash(state); |
| } |
| } |
| |
| #[cfg(feature = "parsing")] |
| pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> { |
| input.step(|cursor| { |
| if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() { |
| let span = g.span(); |
| let delimiter = match g.delimiter() { |
| Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)), |
| Delimiter::Brace => MacroDelimiter::Brace(Brace(span)), |
| Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)), |
| Delimiter::None => { |
| return Err(cursor.error("expected delimiter")); |
| } |
| }; |
| Ok(((delimiter, g.stream().clone()), rest)) |
| } else { |
| Err(cursor.error("expected delimiter")) |
| } |
| }) |
| } |
| |
| #[cfg(feature = "parsing")] |
| pub mod parsing { |
| use super::*; |
| |
| use parse::{Parse, ParseStream, Result}; |
| |
| impl Parse for Macro { |
| fn parse(input: ParseStream) -> Result<Self> { |
| let tts; |
| Ok(Macro { |
| path: input.call(Path::parse_mod_style)?, |
| bang_token: input.parse()?, |
| delimiter: { |
| let (delimiter, content) = parse_delimiter(input)?; |
| tts = content; |
| delimiter |
| }, |
| tts: tts, |
| }) |
| } |
| } |
| } |
| |
| #[cfg(feature = "printing")] |
| mod printing { |
| use super::*; |
| use proc_macro2::TokenStream; |
| use quote::ToTokens; |
| |
| impl ToTokens for Macro { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| self.path.to_tokens(tokens); |
| self.bang_token.to_tokens(tokens); |
| match self.delimiter { |
| MacroDelimiter::Paren(ref paren) => { |
| paren.surround(tokens, |tokens| self.tts.to_tokens(tokens)); |
| } |
| MacroDelimiter::Brace(ref brace) => { |
| brace.surround(tokens, |tokens| self.tts.to_tokens(tokens)); |
| } |
| MacroDelimiter::Bracket(ref bracket) => { |
| bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens)); |
| } |
| } |
| } |
| } |
| } |