blob: 46dc5dd579d67e9f72aea3b6090c9cfd1d1a97dc [file] [log] [blame]
David Tolnayf4bbbd92016-09-23 14:41:55 -07001use super::*;
David Tolnayab919512017-12-30 23:31:51 -05002use proc_macro2::TokenStream;
David Tolnaya7d69fc2018-08-26 13:30:24 -04003#[cfg(feature = "parsing")]
4use proc_macro2::{Delimiter, TokenTree};
David Tolnay61037c62018-01-05 16:21:03 -08005use token::{Brace, Bracket, Paren};
David Tolnay9c76bcb2017-12-26 23:14:59 -05006
David Tolnaya7d69fc2018-08-26 13:30:24 -04007#[cfg(feature = "parsing")]
8use parse::{ParseStream, Result};
David Tolnay9c76bcb2017-12-26 23:14:59 -05009#[cfg(feature = "extra-traits")]
10use std::hash::{Hash, Hasher};
David Tolnayc43b44e2017-12-30 23:55:54 -050011#[cfg(feature = "extra-traits")]
12use tt::TokenStreamHelper;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070013
Alex Crichton62a0a592017-05-22 13:58:53 -070014ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080015 /// A macro invocation: `println!("{}", mac)`.
David Tolnay461d98e2018-01-07 11:07:19 -080016 ///
17 /// *This type is available if Syn is built with the `"derive"` or `"full"`
18 /// feature.*
David Tolnay9c76bcb2017-12-26 23:14:59 -050019 pub struct Macro #manual_extra_traits {
Alex Crichton62a0a592017-05-22 13:58:53 -070020 pub path: Path,
David Tolnayf8db7ba2017-11-11 22:52:16 -080021 pub bang_token: Token![!],
David Tolnayab919512017-12-30 23:31:51 -050022 pub delimiter: MacroDelimiter,
23 pub tts: TokenStream,
24 }
25}
26
27ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -080028 /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
David Tolnay461d98e2018-01-07 11:07:19 -080029 ///
30 /// *This type is available if Syn is built with the `"derive"` or `"full"`
31 /// feature.*
David Tolnayab919512017-12-30 23:31:51 -050032 pub enum MacroDelimiter {
David Tolnayab919512017-12-30 23:31:51 -050033 Paren(Paren),
David Tolnayab919512017-12-30 23:31:51 -050034 Brace(Brace),
David Tolnayab919512017-12-30 23:31:51 -050035 Bracket(Bracket),
Alex Crichton62a0a592017-05-22 13:58:53 -070036 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070037}
38
David Tolnay9c76bcb2017-12-26 23:14:59 -050039#[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 {
David Tolnay65fb5662018-05-20 20:02:28 -070045 self.path == other.path
46 && self.bang_token == other.bang_token
David Tolnayab919512017-12-30 23:31:51 -050047 && self.delimiter == other.delimiter
48 && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
David Tolnay9c76bcb2017-12-26 23:14:59 -050049 }
50}
51
52#[cfg(feature = "extra-traits")]
53impl Hash for Macro {
54 fn hash<H>(&self, state: &mut H)
David Tolnay51382052017-12-27 13:46:21 -050055 where
56 H: Hasher,
David Tolnay9c76bcb2017-12-26 23:14:59 -050057 {
58 self.path.hash(state);
59 self.bang_token.hash(state);
David Tolnayab919512017-12-30 23:31:51 -050060 self.delimiter.hash(state);
61 TokenStreamHelper(&self.tts).hash(state);
David Tolnay9c76bcb2017-12-26 23:14:59 -050062 }
63}
Alex Crichtonccbb45d2017-05-23 10:58:24 -070064
David Tolnay84aa0752016-10-02 23:01:13 -070065#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -040066pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
David Tolnayb50c65a2018-08-30 21:14:57 -070067 input.step(|cursor| {
David Tolnaya7d69fc2018-08-26 13:30:24 -040068 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")]
David Tolnay84aa0752016-10-02 23:01:13 -070086pub mod parsing {
87 use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070088
David Tolnaya7d69fc2018-08-26 13:30:24 -040089 use parse::{Parse, ParseStream, Result};
David Tolnay84aa0752016-10-02 23:01:13 -070090
David Tolnaya7d69fc2018-08-26 13:30:24 -040091 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,
Michael Layzell92639a52017-06-01 00:07:44 -0400103 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800104 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700105 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700106}
David Tolnayf8cf9632016-10-02 23:15:25 -0700107
108#[cfg(feature = "printing")]
109mod printing {
110 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700111 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700112 use quote::ToTokens;
David Tolnayf8cf9632016-10-02 23:15:25 -0700113
David Tolnaydecf28d2017-11-11 11:56:45 -0800114 impl ToTokens for Macro {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700115 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnayf8cf9632016-10-02 23:15:25 -0700116 self.path.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700117 self.bang_token.to_tokens(tokens);
David Tolnayab919512017-12-30 23:31:51 -0500118 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 }
David Tolnayf8cf9632016-10-02 23:15:25 -0700129 }
130 }
David Tolnayf8cf9632016-10-02 23:15:25 -0700131}