1 use super::*;
2 
3 /// Represents a macro invocation. The Path indicates which macro
4 /// is being invoked, and the vector of token-trees contains the source
5 /// of the macro invocation.
6 ///
7 /// NB: the additional ident for a `macro_rules`-style macro is actually
8 /// stored in the enclosing item. Oog.
9 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
10 pub struct Mac {
11     pub path: Path,
12     pub tts: Vec<TokenTree>,
13 }
14 
15 /// When the main rust parser encounters a syntax-extension invocation, it
16 /// parses the arguments to the invocation as a token-tree. This is a very
17 /// loose structure, such that all sorts of different AST-fragments can
18 /// be passed to syntax extensions using a uniform type.
19 ///
20 /// If the syntax extension is an MBE macro, it will attempt to match its
21 /// LHS token tree against the provided token tree, and if it finds a
22 /// match, will transcribe the RHS token tree, splicing in any captured
23 /// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
24 ///
25 /// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
26 /// Nothing special happens to misnamed or misplaced `SubstNt`s.
27 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
28 pub enum TokenTree {
29     /// A single token
30     Token(Token),
31     /// A delimited sequence of token trees
32     Delimited(Delimited),
33 }
34 
35 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
36 pub struct Delimited {
37     /// The type of delimiter
38     pub delim: DelimToken,
39     /// The delimited sequence of token trees
40     pub tts: Vec<TokenTree>,
41 }
42 
43 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
44 pub enum Token {
45     // Expression-operator symbols.
46     Eq,
47     Lt,
48     Le,
49     EqEq,
50     Ne,
51     Ge,
52     Gt,
53     AndAnd,
54     OrOr,
55     Not,
56     Tilde,
57     BinOp(BinOpToken),
58     BinOpEq(BinOpToken),
59 
60     // Structural symbols
61     At,
62     Dot,
63     DotDot,
64     DotDotDot,
65     Comma,
66     Semi,
67     Colon,
68     ModSep,
69     RArrow,
70     LArrow,
71     FatArrow,
72     Pound,
73     Dollar,
74     Question,
75 
76     // Literals
77     Literal(Lit),
78 
79     // Name components
80     Ident(Ident),
81     Underscore,
82     Lifetime(Ident),
83 
84     DocComment(String),
85 }
86 
87 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
88 pub enum BinOpToken {
89     Plus,
90     Minus,
91     Star,
92     Slash,
93     Percent,
94     Caret,
95     And,
96     Or,
97     Shl,
98     Shr,
99 }
100 
101 /// A delimiter token
102 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
103 pub enum DelimToken {
104     /// A round parenthesis: `(` or `)`
105     Paren,
106     /// A square bracket: `[` or `]`
107     Bracket,
108     /// A curly brace: `{` or `}`
109     Brace,
110 }
111 
112 #[cfg(feature = "parsing")]
113 pub mod parsing {
114     use super::*;
115     use Lifetime;
116     use generics::parsing::lifetime;
117     use ident::parsing::word;
118     use lit::parsing::lit;
119     use synom::space::{block_comment, whitespace};
120     use ty::parsing::path;
121 
122     named!(pub mac -> Mac, do_parse!(
123         what: path >>
124         punct!("!") >>
125         body: delimited >>
126         (Mac {
127             path: what,
128             tts: vec![TokenTree::Delimited(body)],
129         })
130     ));
131 
132     named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
133 
134     named!(pub delimited -> Delimited, alt!(
135         delimited!(
136             punct!("("),
137             token_trees,
138             punct!(")")
139         ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
140         |
141         delimited!(
142             punct!("["),
143             token_trees,
144             punct!("]")
145         ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
146         |
147         delimited!(
148             punct!("{"),
149             token_trees,
150             punct!("}")
151         ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
152     ));
153 
154     named!(pub token_tree -> TokenTree, alt!(
155         map!(token, TokenTree::Token)
156         |
157         map!(delimited, TokenTree::Delimited)
158     ));
159 
160     named!(token -> Token, alt!(
161         keyword!("_") => { |_| Token::Underscore }
162         |
163         punct!("&&") => { |_| Token::AndAnd } // must be before BinOp
164         |
165         punct!("||") => { |_| Token::OrOr } // must be before BinOp
166         |
167         punct!("->") => { |_| Token::RArrow } // must be before BinOp
168         |
169         punct!("<-") => { |_| Token::LArrow } // must be before Lt
170         |
171         punct!("=>") => { |_| Token::FatArrow } // must be before Eq
172         |
173         punct!("...") => { |_| Token::DotDotDot } // must be before DotDot
174         |
175         punct!("..") => { |_| Token::DotDot } // must be before Dot
176         |
177         punct!(".") => { |_| Token::Dot }
178         |
179         map!(doc_comment, Token::DocComment) // must be before bin_op
180         |
181         map!(bin_op_eq, Token::BinOpEq) // must be before bin_op
182         |
183         map!(bin_op, Token::BinOp)
184         |
185         map!(lit, Token::Literal)
186         |
187         map!(word, Token::Ident)
188         |
189         map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
190         |
191         punct!("<=") => { |_| Token::Le }
192         |
193         punct!("==") => { |_| Token::EqEq }
194         |
195         punct!("!=") => { |_| Token::Ne }
196         |
197         punct!(">=") => { |_| Token::Ge }
198         |
199         punct!("::") => { |_| Token::ModSep }
200         |
201         punct!("=") => { |_| Token::Eq }
202         |
203         punct!("<") => { |_| Token::Lt }
204         |
205         punct!(">") => { |_| Token::Gt }
206         |
207         punct!("!") => { |_| Token::Not }
208         |
209         punct!("~") => { |_| Token::Tilde }
210         |
211         punct!("@") => { |_| Token::At }
212         |
213         punct!(",") => { |_| Token::Comma }
214         |
215         punct!(";") => { |_| Token::Semi }
216         |
217         punct!(":") => { |_| Token::Colon }
218         |
219         punct!("#") => { |_| Token::Pound }
220         |
221         punct!("$") => { |_| Token::Dollar }
222         |
223         punct!("?") => { |_| Token::Question }
224     ));
225 
226     named!(bin_op -> BinOpToken, alt!(
227         punct!("+") => { |_| BinOpToken::Plus }
228         |
229         punct!("-") => { |_| BinOpToken::Minus }
230         |
231         punct!("*") => { |_| BinOpToken::Star }
232         |
233         punct!("/") => { |_| BinOpToken::Slash }
234         |
235         punct!("%") => { |_| BinOpToken::Percent }
236         |
237         punct!("^") => { |_| BinOpToken::Caret }
238         |
239         punct!("&") => { |_| BinOpToken::And }
240         |
241         punct!("|") => { |_| BinOpToken::Or }
242         |
243         punct!("<<") => { |_| BinOpToken::Shl }
244         |
245         punct!(">>") => { |_| BinOpToken::Shr }
246     ));
247 
248     named!(bin_op_eq -> BinOpToken, alt!(
249         punct!("+=") => { |_| BinOpToken::Plus }
250         |
251         punct!("-=") => { |_| BinOpToken::Minus }
252         |
253         punct!("*=") => { |_| BinOpToken::Star }
254         |
255         punct!("/=") => { |_| BinOpToken::Slash }
256         |
257         punct!("%=") => { |_| BinOpToken::Percent }
258         |
259         punct!("^=") => { |_| BinOpToken::Caret }
260         |
261         punct!("&=") => { |_| BinOpToken::And }
262         |
263         punct!("|=") => { |_| BinOpToken::Or }
264         |
265         punct!("<<=") => { |_| BinOpToken::Shl }
266         |
267         punct!(">>=") => { |_| BinOpToken::Shr }
268     ));
269 
270     named!(doc_comment -> String, alt!(
271         do_parse!(
272             punct!("//!") >>
273             content: take_until!("\n") >>
274             (format!("//!{}", content))
275         )
276         |
277         do_parse!(
278             option!(whitespace) >>
279             peek!(tag!("/*!")) >>
280             com: block_comment >>
281             (com.to_owned())
282         )
283         |
284         do_parse!(
285             punct!("///") >>
286             not!(tag!("/")) >>
287             content: take_until!("\n") >>
288             (format!("///{}", content))
289         )
290         |
291         do_parse!(
292             option!(whitespace) >>
293             peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
294             com: block_comment >>
295             (com.to_owned())
296         )
297     ));
298 }
299 
300 #[cfg(feature = "printing")]
301 mod printing {
302     use super::*;
303     use quote::{Tokens, ToTokens};
304 
305     impl ToTokens for Mac {
to_tokens(&self, tokens: &mut Tokens)306         fn to_tokens(&self, tokens: &mut Tokens) {
307             self.path.to_tokens(tokens);
308             tokens.append("!");
309             for tt in &self.tts {
310                 tt.to_tokens(tokens);
311             }
312         }
313     }
314 
315     impl ToTokens for TokenTree {
to_tokens(&self, tokens: &mut Tokens)316         fn to_tokens(&self, tokens: &mut Tokens) {
317             match *self {
318                 TokenTree::Token(ref token) => token.to_tokens(tokens),
319                 TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
320             }
321         }
322     }
323 
324     impl DelimToken {
open(&self) -> &'static str325         fn open(&self) -> &'static str {
326             match *self {
327                 DelimToken::Paren => "(",
328                 DelimToken::Bracket => "[",
329                 DelimToken::Brace => "{",
330             }
331         }
332 
close(&self) -> &'static str333         fn close(&self) -> &'static str {
334             match *self {
335                 DelimToken::Paren => ")",
336                 DelimToken::Bracket => "]",
337                 DelimToken::Brace => "}",
338             }
339         }
340     }
341 
342     impl ToTokens for Delimited {
to_tokens(&self, tokens: &mut Tokens)343         fn to_tokens(&self, tokens: &mut Tokens) {
344             tokens.append(self.delim.open());
345             for tt in &self.tts {
346                 tt.to_tokens(tokens);
347             }
348             tokens.append(self.delim.close());
349         }
350     }
351 
352     impl ToTokens for Token {
to_tokens(&self, tokens: &mut Tokens)353         fn to_tokens(&self, tokens: &mut Tokens) {
354             match *self {
355                 Token::Eq => tokens.append("="),
356                 Token::Lt => tokens.append("<"),
357                 Token::Le => tokens.append("<="),
358                 Token::EqEq => tokens.append("=="),
359                 Token::Ne => tokens.append("!="),
360                 Token::Ge => tokens.append(">="),
361                 Token::Gt => tokens.append(">"),
362                 Token::AndAnd => tokens.append("&&"),
363                 Token::OrOr => tokens.append("||"),
364                 Token::Not => tokens.append("!"),
365                 Token::Tilde => tokens.append("~"),
366                 Token::BinOp(binop) => tokens.append(binop.op()),
367                 Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
368                 Token::At => tokens.append("@"),
369                 Token::Dot => tokens.append("."),
370                 Token::DotDot => tokens.append(".."),
371                 Token::DotDotDot => tokens.append("..."),
372                 Token::Comma => tokens.append(","),
373                 Token::Semi => tokens.append(";"),
374                 Token::Colon => tokens.append(":"),
375                 Token::ModSep => tokens.append("::"),
376                 Token::RArrow => tokens.append("->"),
377                 Token::LArrow => tokens.append("<-"),
378                 Token::FatArrow => tokens.append("=>"),
379                 Token::Pound => tokens.append("#"),
380                 Token::Dollar => tokens.append("$"),
381                 Token::Question => tokens.append("?"),
382                 Token::Literal(ref lit) => lit.to_tokens(tokens),
383                 Token::Ident(ref ident) |
384                 Token::Lifetime(ref ident) => ident.to_tokens(tokens),
385                 Token::Underscore => tokens.append("_"),
386                 Token::DocComment(ref com) => {
387                     tokens.append(&format!("{}\n", com));
388                 }
389             }
390         }
391     }
392 
393     impl BinOpToken {
op(&self) -> &'static str394         fn op(&self) -> &'static str {
395             match *self {
396                 BinOpToken::Plus => "+",
397                 BinOpToken::Minus => "-",
398                 BinOpToken::Star => "*",
399                 BinOpToken::Slash => "/",
400                 BinOpToken::Percent => "%",
401                 BinOpToken::Caret => "^",
402                 BinOpToken::And => "&",
403                 BinOpToken::Or => "|",
404                 BinOpToken::Shl => "<<",
405                 BinOpToken::Shr => ">>",
406             }
407         }
408 
assign_op(&self) -> &'static str409         fn assign_op(&self) -> &'static str {
410             match *self {
411                 BinOpToken::Plus => "+=",
412                 BinOpToken::Minus => "-=",
413                 BinOpToken::Star => "*=",
414                 BinOpToken::Slash => "/=",
415                 BinOpToken::Percent => "%=",
416                 BinOpToken::Caret => "^=",
417                 BinOpToken::And => "&=",
418                 BinOpToken::Or => "|=",
419                 BinOpToken::Shl => "<<=",
420                 BinOpToken::Shr => ">>=",
421             }
422         }
423     }
424 
425     impl ToTokens for BinOpToken {
to_tokens(&self, tokens: &mut Tokens)426         fn to_tokens(&self, tokens: &mut Tokens) {
427             tokens.append(self.op());
428         }
429     }
430 }
431