blob: 234969ab5d03d9c0e6fc071e1ca81bb7603560fa [file] [log] [blame]
Alex Crichtonccbb45d2017-05-23 10:58:24 -07001#[cfg(feature = "extra-traits")]
2use std::fmt;
3
David Tolnayf4bbbd92016-09-23 14:41:55 -07004use super::*;
5
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -07006use proc_macro2::{TokenNode, Delimiter};
Alex Crichtonccbb45d2017-05-23 10:58:24 -07007
Alex Crichton62a0a592017-05-22 13:58:53 -07008ast_struct! {
9 /// Represents a macro invocation. The Path indicates which macro
10 /// is being invoked, and the vector of token-trees contains the source
11 /// of the macro invocation.
David Tolnaydecf28d2017-11-11 11:56:45 -080012 pub struct Macro {
Alex Crichton62a0a592017-05-22 13:58:53 -070013 pub path: Path,
David Tolnayf8db7ba2017-11-11 22:52:16 -080014 pub bang_token: Token![!],
Alex Crichtonccbb45d2017-05-23 10:58:24 -070015 pub tokens: Vec<TokenTree>,
Alex Crichton62a0a592017-05-22 13:58:53 -070016 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070017}
18
Alex Crichtonccbb45d2017-05-23 10:58:24 -070019#[cfg_attr(feature = "clone-impls", derive(Clone))]
20pub struct TokenTree(pub proc_macro2::TokenTree);
21
David Tolnaydecf28d2017-11-11 11:56:45 -080022impl Macro {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070023 pub fn is_braced(&self) -> bool {
24 match self.tokens.last() {
25 Some(t) => t.is_braced(),
26 None => false,
27 }
Alex Crichton62a0a592017-05-22 13:58:53 -070028 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070029}
30
Alex Crichtonccbb45d2017-05-23 10:58:24 -070031impl TokenTree {
32 pub fn is_braced(&self) -> bool {
33 match self.0.kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070034 TokenNode::Group(Delimiter::Brace, _) => true,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070035 _ => false,
36 }
Alex Crichton62a0a592017-05-22 13:58:53 -070037 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070038}
39
Alex Crichtonccbb45d2017-05-23 10:58:24 -070040#[cfg(feature = "extra-traits")]
41impl PartialEq for TokenTree {
42 fn eq(&self, other: &TokenTree) -> bool {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070043 use proc_macro2::Spacing;
David Tolnayf4bbbd92016-09-23 14:41:55 -070044
Alex Crichtonccbb45d2017-05-23 10:58:24 -070045 match (&self.0.kind, &other.0.kind) {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070046 (&TokenNode::Group(d1, ref s1), &TokenNode::Group(d2, ref s2)) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070047 match (d1, d2) {
48 (Delimiter::Parenthesis, Delimiter::Parenthesis) |
49 (Delimiter::Brace, Delimiter::Brace) |
50 (Delimiter::Bracket, Delimiter::Bracket) => {}
51 (Delimiter::None, Delimiter::None) => {}
52 _ => return false,
53 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070054
Alex Crichtonccbb45d2017-05-23 10:58:24 -070055 let s1 = s1.clone().into_iter();
56 let mut s2 = s2.clone().into_iter();
David Tolnayf4bbbd92016-09-23 14:41:55 -070057
Alex Crichtonccbb45d2017-05-23 10:58:24 -070058 for item1 in s1 {
59 let item2 = match s2.next() {
60 Some(item) => item,
61 None => return false,
62 };
63 if TokenTree(item1) != TokenTree(item2) {
64 return false
65 }
66 }
67 s2.next().is_none()
68 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070069 (&TokenNode::Op(o1, k1), &TokenNode::Op(o2, k2)) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070070 o1 == o2 && match (k1, k2) {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070071 (Spacing::Alone, Spacing::Alone) |
72 (Spacing::Joint, Spacing::Joint) => true,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070073 _ => false,
74 }
75 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070076 (&TokenNode::Literal(ref l1), &TokenNode::Literal(ref l2)) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070077 l1.to_string() == l2.to_string()
78 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070079 (&TokenNode::Term(ref s1), &TokenNode::Term(ref s2)) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070080 s1.as_str() == s2.as_str()
81 }
82 _ => false,
83 }
Alex Crichton62a0a592017-05-22 13:58:53 -070084 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070085}
86
Alex Crichtonccbb45d2017-05-23 10:58:24 -070087#[cfg(feature = "extra-traits")]
88impl Eq for TokenTree {}
89
90#[cfg(feature = "extra-traits")]
91impl ::std::hash::Hash for TokenTree {
92 fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070093 use proc_macro2::Spacing;
Alex Crichtonccbb45d2017-05-23 10:58:24 -070094
95 match self.0.kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -070096 TokenNode::Group(delim, ref stream) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070097 0u8.hash(h);
98 match delim {
99 Delimiter::Parenthesis => 0u8.hash(h),
100 Delimiter::Brace => 1u8.hash(h),
101 Delimiter::Bracket => 2u8.hash(h),
102 Delimiter::None => 3u8.hash(h),
103 }
104
105 for item in stream.clone().into_iter() {
106 TokenTree(item).hash(h);
107 }
108 0xffu8.hash(h); // terminator w/ a variant we don't normally hash
109 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700110 TokenNode::Op(op, kind) => {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700111 1u8.hash(h);
112 op.hash(h);
113 match kind {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700114 Spacing::Alone => 0u8.hash(h),
115 Spacing::Joint => 1u8.hash(h),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700116 }
117 }
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700118 TokenNode::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
119 TokenNode::Term(ref word) => (3u8, word.as_str()).hash(h),
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700120 }
Alex Crichton62a0a592017-05-22 13:58:53 -0700121 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700122}
123
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700124#[cfg(feature = "extra-traits")]
125impl fmt::Debug for TokenTree {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 self.0.to_string().fmt(f)
Alex Crichton62a0a592017-05-22 13:58:53 -0700128 }
David Tolnay84aa0752016-10-02 23:01:13 -0700129}
130
131#[cfg(feature = "parsing")]
132pub mod parsing {
133 use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700134
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700135 use proc_macro2::{TokenNode, TokenTree};
Michael Layzell92639a52017-06-01 00:07:44 -0400136 use synom::{Synom, PResult, Cursor, parse_error};
David Tolnay84aa0752016-10-02 23:01:13 -0700137
David Tolnaydecf28d2017-11-11 11:56:45 -0800138 impl Synom for Macro {
Michael Layzell92639a52017-06-01 00:07:44 -0400139 named!(parse -> Self, do_parse!(
140 what: syn!(Path) >>
David Tolnayf8db7ba2017-11-11 22:52:16 -0800141 bang: punct!(!) >>
Michael Layzell92639a52017-06-01 00:07:44 -0400142 body: call!(::TokenTree::parse_delimited) >>
David Tolnaydecf28d2017-11-11 11:56:45 -0800143 (Macro {
Michael Layzell92639a52017-06-01 00:07:44 -0400144 path: what,
145 bang_token: bang,
146 tokens: vec![body],
147 })
148 ));
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700149 }
150
Alex Crichton954046c2017-05-30 21:49:42 -0700151 impl ::TokenTree {
Michael Layzell92639a52017-06-01 00:07:44 -0400152 pub fn parse_list(input: Cursor) -> PResult<Vec<Self>> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400153 Ok((Cursor::empty(), input.token_stream().into_iter().map(::TokenTree).collect()))
Alex Crichton954046c2017-05-30 21:49:42 -0700154 }
155
Michael Layzell92639a52017-06-01 00:07:44 -0400156 pub fn parse_delimited(input: Cursor) -> PResult<Self> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400157 match input.token_tree() {
Alex Crichtonf9e8f1a2017-07-05 18:20:44 -0700158 Some((rest, token @ TokenTree { kind: TokenNode::Group(..), .. })) => {
Michael Layzell589a8f42017-06-02 19:47:01 -0400159 Ok((rest, ::TokenTree(token)))
Alex Crichton954046c2017-05-30 21:49:42 -0700160 }
Michael Layzell92639a52017-06-01 00:07:44 -0400161 _ => parse_error(),
Alex Crichton954046c2017-05-30 21:49:42 -0700162 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700163 }
164 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700165}
David Tolnayf8cf9632016-10-02 23:15:25 -0700166
167#[cfg(feature = "printing")]
168mod printing {
169 use super::*;
170 use quote::{Tokens, ToTokens};
171
David Tolnaydecf28d2017-11-11 11:56:45 -0800172 impl ToTokens for Macro {
David Tolnayf8cf9632016-10-02 23:15:25 -0700173 fn to_tokens(&self, tokens: &mut Tokens) {
174 self.path.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700175 self.bang_token.to_tokens(tokens);
176 tokens.append_all(&self.tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700177 }
178 }
179
180 impl ToTokens for TokenTree {
181 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700182 self.0.to_tokens(tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700183 }
184 }
185}