blob: 5e6d02e003ec1e671c57e9dcf2fa486f1e8d9bd7 [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 Crichtonccbb45d2017-05-23 10:58:24 -07006use proc_macro2::{TokenKind, Delimiter};
7
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.
12 ///
13 /// NB: the additional ident for a `macro_rules`-style macro is actually
14 /// stored in the enclosing item. Oog.
15 pub struct Mac {
16 pub path: Path,
Alex Crichtonccbb45d2017-05-23 10:58:24 -070017 pub bang_token: tokens::Bang,
18 pub tokens: Vec<TokenTree>,
Alex Crichton62a0a592017-05-22 13:58:53 -070019 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070020}
21
Alex Crichtonccbb45d2017-05-23 10:58:24 -070022#[cfg_attr(feature = "clone-impls", derive(Clone))]
23pub struct TokenTree(pub proc_macro2::TokenTree);
24
25impl Mac {
26 pub fn is_braced(&self) -> bool {
27 match self.tokens.last() {
28 Some(t) => t.is_braced(),
29 None => false,
30 }
Alex Crichton62a0a592017-05-22 13:58:53 -070031 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070032}
33
Alex Crichtonccbb45d2017-05-23 10:58:24 -070034impl TokenTree {
35 pub fn is_braced(&self) -> bool {
36 match self.0.kind {
37 TokenKind::Sequence(Delimiter::Brace, _) => true,
38 _ => false,
39 }
Alex Crichton62a0a592017-05-22 13:58:53 -070040 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070041}
42
Alex Crichtonccbb45d2017-05-23 10:58:24 -070043#[cfg(feature = "extra-traits")]
44impl PartialEq for TokenTree {
45 fn eq(&self, other: &TokenTree) -> bool {
46 use proc_macro2::OpKind;
David Tolnayf4bbbd92016-09-23 14:41:55 -070047
Alex Crichtonccbb45d2017-05-23 10:58:24 -070048 match (&self.0.kind, &other.0.kind) {
49 (&TokenKind::Sequence(d1, ref s1), &TokenKind::Sequence(d2, ref s2)) => {
50 match (d1, d2) {
51 (Delimiter::Parenthesis, Delimiter::Parenthesis) |
52 (Delimiter::Brace, Delimiter::Brace) |
53 (Delimiter::Bracket, Delimiter::Bracket) => {}
54 (Delimiter::None, Delimiter::None) => {}
55 _ => return false,
56 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070057
Alex Crichtonccbb45d2017-05-23 10:58:24 -070058 let s1 = s1.clone().into_iter();
59 let mut s2 = s2.clone().into_iter();
David Tolnayf4bbbd92016-09-23 14:41:55 -070060
Alex Crichtonccbb45d2017-05-23 10:58:24 -070061 for item1 in s1 {
62 let item2 = match s2.next() {
63 Some(item) => item,
64 None => return false,
65 };
66 if TokenTree(item1) != TokenTree(item2) {
67 return false
68 }
69 }
70 s2.next().is_none()
71 }
72 (&TokenKind::Op(o1, k1), &TokenKind::Op(o2, k2)) => {
73 o1 == o2 && match (k1, k2) {
74 (OpKind::Alone, OpKind::Alone) |
75 (OpKind::Joint, OpKind::Joint) => true,
76 _ => false,
77 }
78 }
79 (&TokenKind::Literal(ref l1), &TokenKind::Literal(ref l2)) => {
80 l1.to_string() == l2.to_string()
81 }
82 (&TokenKind::Word(ref s1), &TokenKind::Word(ref s2)) => {
83 s1.as_str() == s2.as_str()
84 }
85 _ => false,
86 }
Alex Crichton62a0a592017-05-22 13:58:53 -070087 }
David Tolnayf4bbbd92016-09-23 14:41:55 -070088}
89
Alex Crichtonccbb45d2017-05-23 10:58:24 -070090#[cfg(feature = "extra-traits")]
91impl Eq for TokenTree {}
92
93#[cfg(feature = "extra-traits")]
94impl ::std::hash::Hash for TokenTree {
95 fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
96 use proc_macro2::OpKind;
97
98 match self.0.kind {
99 TokenKind::Sequence(delim, ref stream) => {
100 0u8.hash(h);
101 match delim {
102 Delimiter::Parenthesis => 0u8.hash(h),
103 Delimiter::Brace => 1u8.hash(h),
104 Delimiter::Bracket => 2u8.hash(h),
105 Delimiter::None => 3u8.hash(h),
106 }
107
108 for item in stream.clone().into_iter() {
109 TokenTree(item).hash(h);
110 }
111 0xffu8.hash(h); // terminator w/ a variant we don't normally hash
112 }
113 TokenKind::Op(op, kind) => {
114 1u8.hash(h);
115 op.hash(h);
116 match kind {
117 OpKind::Alone => 0u8.hash(h),
118 OpKind::Joint => 1u8.hash(h),
119 }
120 }
121 TokenKind::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
122 TokenKind::Word(ref word) => (3u8, word.as_str()).hash(h),
123 }
Alex Crichton62a0a592017-05-22 13:58:53 -0700124 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700125}
126
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700127#[cfg(feature = "extra-traits")]
128impl fmt::Debug for TokenTree {
129 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130 self.0.to_string().fmt(f)
Alex Crichton62a0a592017-05-22 13:58:53 -0700131 }
David Tolnay84aa0752016-10-02 23:01:13 -0700132}
133
134#[cfg(feature = "parsing")]
135pub mod parsing {
136 use super::*;
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700137
Alex Crichton954046c2017-05-30 21:49:42 -0700138 use proc_macro2::{TokenKind, TokenTree};
139 use synom::tokens::*;
140 use synom::{Synom, IResult};
David Tolnay84aa0752016-10-02 23:01:13 -0700141
Alex Crichton954046c2017-05-30 21:49:42 -0700142 impl Synom for Mac {
143 fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
144 do_parse! {
145 input,
146 what: syn!(Path) >>
147 bang: syn!(Bang) >>
148 body: call!(::TokenTree::parse_delimited) >>
149 (Mac {
150 path: what,
151 bang_token: bang,
152 tokens: vec![body],
153 })
154 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700155 }
156 }
157
Alex Crichton954046c2017-05-30 21:49:42 -0700158 impl ::TokenTree {
159 pub fn parse_list(input: &[TokenTree]) -> IResult<&[TokenTree], Vec<Self>> {
160 IResult::Done(&[], input.iter().cloned().map(::TokenTree).collect())
161 }
162
163 pub fn parse_delimited(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
164 let mut tokens = input.iter();
165 match tokens.next() {
166 Some(token @ &TokenTree { kind: TokenKind::Sequence(..), .. }) => {
167 IResult::Done(tokens.as_slice(), ::TokenTree(token.clone()))
168 }
169 _ => IResult::Error,
170 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700171 }
172 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700173}
David Tolnayf8cf9632016-10-02 23:15:25 -0700174
175#[cfg(feature = "printing")]
176mod printing {
177 use super::*;
178 use quote::{Tokens, ToTokens};
179
180 impl ToTokens for Mac {
181 fn to_tokens(&self, tokens: &mut Tokens) {
182 self.path.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700183 self.bang_token.to_tokens(tokens);
184 tokens.append_all(&self.tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700185 }
186 }
187
188 impl ToTokens for TokenTree {
189 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700190 self.0.to_tokens(tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700191 }
192 }
193}