blob: 4bffb55942796daea2890699983e51186f5f53aa [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnayf4bbbd92016-09-23 14:41:55 -07009use super::*;
David Tolnayab919512017-12-30 23:31:51 -050010use proc_macro2::TokenStream;
David Tolnaya7d69fc2018-08-26 13:30:24 -040011#[cfg(feature = "parsing")]
12use proc_macro2::{Delimiter, TokenTree};
David Tolnay61037c62018-01-05 16:21:03 -080013use token::{Brace, Bracket, Paren};
David Tolnay9c76bcb2017-12-26 23:14:59 -050014
David Tolnaya7d69fc2018-08-26 13:30:24 -040015#[cfg(feature = "parsing")]
16use parse::{ParseStream, Result};
David Tolnay9c76bcb2017-12-26 23:14:59 -050017#[cfg(feature = "extra-traits")]
18use std::hash::{Hash, Hasher};
David Tolnayc43b44e2017-12-30 23:55:54 -050019#[cfg(feature = "extra-traits")]
20use tt::TokenStreamHelper;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070021
Alex Crichton62a0a592017-05-22 13:58:53 -070022ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080023 /// A macro invocation: `println!("{}", mac)`.
David Tolnay461d98e2018-01-07 11:07:19 -080024 ///
25 /// *This type is available if Syn is built with the `"derive"` or `"full"`
26 /// feature.*
David Tolnay9c76bcb2017-12-26 23:14:59 -050027 pub struct Macro #manual_extra_traits {
Alex Crichton62a0a592017-05-22 13:58:53 -070028 pub path: Path,
David Tolnayf8db7ba2017-11-11 22:52:16 -080029 pub bang_token: Token![!],
David Tolnayab919512017-12-30 23:31:51 -050030 pub delimiter: MacroDelimiter,
31 pub tts: TokenStream,
32 }
33}
34
35ast_enum! {
David Tolnay05658502018-01-07 09:56:37 -080036 /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
David Tolnay461d98e2018-01-07 11:07:19 -080037 ///
38 /// *This type is available if Syn is built with the `"derive"` or `"full"`
39 /// feature.*
David Tolnayab919512017-12-30 23:31:51 -050040 pub enum MacroDelimiter {
David Tolnayab919512017-12-30 23:31:51 -050041 Paren(Paren),
David Tolnayab919512017-12-30 23:31:51 -050042 Brace(Brace),
David Tolnayab919512017-12-30 23:31:51 -050043 Bracket(Bracket),
Alex Crichton62a0a592017-05-22 13:58:53 -070044 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070045}
46
David Tolnay9c76bcb2017-12-26 23:14:59 -050047#[cfg(feature = "extra-traits")]
48impl Eq for Macro {}
49
50#[cfg(feature = "extra-traits")]
51impl PartialEq for Macro {
52 fn eq(&self, other: &Self) -> bool {
David Tolnay65fb5662018-05-20 20:02:28 -070053 self.path == other.path
54 && self.bang_token == other.bang_token
David Tolnayab919512017-12-30 23:31:51 -050055 && self.delimiter == other.delimiter
56 && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
David Tolnay9c76bcb2017-12-26 23:14:59 -050057 }
58}
59
60#[cfg(feature = "extra-traits")]
61impl Hash for Macro {
62 fn hash<H>(&self, state: &mut H)
David Tolnay51382052017-12-27 13:46:21 -050063 where
64 H: Hasher,
David Tolnay9c76bcb2017-12-26 23:14:59 -050065 {
66 self.path.hash(state);
67 self.bang_token.hash(state);
David Tolnayab919512017-12-30 23:31:51 -050068 self.delimiter.hash(state);
69 TokenStreamHelper(&self.tts).hash(state);
David Tolnay9c76bcb2017-12-26 23:14:59 -050070 }
71}
Alex Crichtonccbb45d2017-05-23 10:58:24 -070072
David Tolnay84aa0752016-10-02 23:01:13 -070073#[cfg(feature = "parsing")]
David Tolnaya7d69fc2018-08-26 13:30:24 -040074pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
David Tolnayb50c65a2018-08-30 21:14:57 -070075 input.step(|cursor| {
David Tolnaya7d69fc2018-08-26 13:30:24 -040076 if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
77 let span = g.span();
78 let delimiter = match g.delimiter() {
79 Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
80 Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
81 Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
82 Delimiter::None => {
83 return Err(cursor.error("expected delimiter"));
84 }
85 };
86 Ok(((delimiter, g.stream().clone()), rest))
87 } else {
88 Err(cursor.error("expected delimiter"))
89 }
90 })
91}
92
93#[cfg(feature = "parsing")]
David Tolnay84aa0752016-10-02 23:01:13 -070094pub mod parsing {
95 use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070096
David Tolnaya7d69fc2018-08-26 13:30:24 -040097 use parse::{Parse, ParseStream, Result};
David Tolnay84aa0752016-10-02 23:01:13 -070098
David Tolnaya7d69fc2018-08-26 13:30:24 -040099 impl Parse for Macro {
100 fn parse(input: ParseStream) -> Result<Self> {
101 let tts;
102 Ok(Macro {
103 path: input.call(Path::parse_mod_style)?,
104 bang_token: input.parse()?,
105 delimiter: {
106 let (delimiter, content) = parse_delimiter(input)?;
107 tts = content;
108 delimiter
109 },
110 tts: tts,
Michael Layzell92639a52017-06-01 00:07:44 -0400111 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800112 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700113 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700114}
David Tolnayf8cf9632016-10-02 23:15:25 -0700115
116#[cfg(feature = "printing")]
117mod printing {
118 use super::*;
Alex Crichtona74a1c82018-05-16 10:20:44 -0700119 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700120 use quote::ToTokens;
David Tolnayf8cf9632016-10-02 23:15:25 -0700121
David Tolnaydecf28d2017-11-11 11:56:45 -0800122 impl ToTokens for Macro {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700123 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnayf8cf9632016-10-02 23:15:25 -0700124 self.path.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700125 self.bang_token.to_tokens(tokens);
David Tolnayab919512017-12-30 23:31:51 -0500126 match self.delimiter {
127 MacroDelimiter::Paren(ref paren) => {
128 paren.surround(tokens, |tokens| self.tts.to_tokens(tokens));
129 }
130 MacroDelimiter::Brace(ref brace) => {
131 brace.surround(tokens, |tokens| self.tts.to_tokens(tokens));
132 }
133 MacroDelimiter::Bracket(ref bracket) => {
134 bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens));
135 }
136 }
David Tolnayf8cf9632016-10-02 23:15:25 -0700137 }
138 }
David Tolnayf8cf9632016-10-02 23:15:25 -0700139}