blob: 3517ac8cebe9bfb8d66f1bf4ccaa0540725152a2 [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::*;
Michael Layzell92639a52017-06-01 00:07:44 -0400140 use synom::{Synom, PResult, Cursor, parse_error};
David Tolnay84aa0752016-10-02 23:01:13 -0700141
Alex Crichton954046c2017-05-30 21:49:42 -0700142 impl Synom for Mac {
Michael Layzell92639a52017-06-01 00:07:44 -0400143 named!(parse -> Self, do_parse!(
144 what: syn!(Path) >>
145 bang: syn!(Bang) >>
146 body: call!(::TokenTree::parse_delimited) >>
147 (Mac {
148 path: what,
149 bang_token: bang,
150 tokens: vec![body],
151 })
152 ));
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700153 }
154
Alex Crichton954046c2017-05-30 21:49:42 -0700155 impl ::TokenTree {
Michael Layzell92639a52017-06-01 00:07:44 -0400156 pub fn parse_list(input: Cursor) -> PResult<Vec<Self>> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400157 Ok((Cursor::empty(), input.token_stream().into_iter().map(::TokenTree).collect()))
Alex Crichton954046c2017-05-30 21:49:42 -0700158 }
159
Michael Layzell92639a52017-06-01 00:07:44 -0400160 pub fn parse_delimited(input: Cursor) -> PResult<Self> {
Michael Layzell589a8f42017-06-02 19:47:01 -0400161 match input.token_tree() {
162 Some((rest, token @ TokenTree { kind: TokenKind::Sequence(..), .. })) => {
163 Ok((rest, ::TokenTree(token)))
Alex Crichton954046c2017-05-30 21:49:42 -0700164 }
Michael Layzell92639a52017-06-01 00:07:44 -0400165 _ => parse_error(),
Alex Crichton954046c2017-05-30 21:49:42 -0700166 }
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700167 }
168 }
David Tolnayf4bbbd92016-09-23 14:41:55 -0700169}
David Tolnayf8cf9632016-10-02 23:15:25 -0700170
171#[cfg(feature = "printing")]
172mod printing {
173 use super::*;
174 use quote::{Tokens, ToTokens};
175
176 impl ToTokens for Mac {
177 fn to_tokens(&self, tokens: &mut Tokens) {
178 self.path.to_tokens(tokens);
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700179 self.bang_token.to_tokens(tokens);
180 tokens.append_all(&self.tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700181 }
182 }
183
184 impl ToTokens for TokenTree {
185 fn to_tokens(&self, tokens: &mut Tokens) {
Alex Crichtonccbb45d2017-05-23 10:58:24 -0700186 self.0.to_tokens(tokens);
David Tolnayf8cf9632016-10-02 23:15:25 -0700187 }
188 }
189}