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 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 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}