blob: e96bdcf16b802f031984076427f1e72e255e6b1d [file] [log] [blame]
David Tolnayf4bbbd92016-09-23 14:41:55 -07001use 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///
David Tolnayaed77b02016-09-23 20:50:31 -07007/// NB: the additional ident for a `macro_rules`-style macro is actually
David Tolnayf4bbbd92016-09-23 14:41:55 -07008/// stored in the enclosing item. Oog.
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub 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
David Tolnayaed77b02016-09-23 20:50:31 -070023/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
David Tolnayf4bbbd92016-09-23 14:41:55 -070024///
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)]
28pub enum TokenTree {
29 /// A single token
30 Token(Token),
31 /// A delimited sequence of token trees
32 Delimited(Delimited),
David Tolnayf4bbbd92016-09-23 14:41:55 -070033}
34
35#[derive(Debug, Clone, Eq, PartialEq)]
36pub 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)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070044pub enum Token {
David Tolnaydaaf7742016-10-03 11:11:43 -070045 // Expression-operator symbols.
David Tolnayf4bbbd92016-09-23 14:41:55 -070046 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
David Tolnaydaaf7742016-10-03 11:11:43 -070060 // Structural symbols
David Tolnayf4bbbd92016-09-23 14:41:55 -070061 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,
David Tolnayf4bbbd92016-09-23 14:41:55 -070075
David Tolnaydaaf7742016-10-03 11:11:43 -070076 // Literals
David Tolnay84aa0752016-10-02 23:01:13 -070077 Literal(Lit),
David Tolnayf4bbbd92016-09-23 14:41:55 -070078
David Tolnaydaaf7742016-10-03 11:11:43 -070079 // Name components
David Tolnayf4bbbd92016-09-23 14:41:55 -070080 Ident(Ident),
81 Underscore,
82 Lifetime(Ident),
83
David Tolnayf4bbbd92016-09-23 14:41:55 -070084 DocComment(String),
David Tolnayf4bbbd92016-09-23 14:41:55 -070085}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88pub 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)]
103pub enum DelimToken {
104 /// A round parenthesis: `(` or `)`
105 Paren,
106 /// A square bracket: `[` or `]`
107 Bracket,
108 /// A curly brace: `{` or `}`
109 Brace,
David Tolnay84aa0752016-10-02 23:01:13 -0700110}
111
112#[cfg(feature = "parsing")]
113pub mod parsing {
114 use super::*;
115 use Lifetime;
116 use generics::parsing::lifetime;
117 use ident::parsing::ident;
118 use lit::parsing::lit;
119 use space::{block_comment, whitespace};
120
121 named!(pub mac -> Mac, do_parse!(
122 name: ident >>
123 punct!("!") >>
124 body: delimited >>
125 (Mac {
126 path: name.into(),
127 tts: vec![TokenTree::Delimited(body)],
128 })
129 ));
130
David Tolnayf5fdfa02016-10-23 15:25:17 -0700131 named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
Simon Sapin095a42b2016-10-20 15:54:23 +0200132
David Tolnay84aa0752016-10-02 23:01:13 -0700133 named!(pub delimited -> Delimited, alt!(
134 delimited!(
135 punct!("("),
136 many0!(token_tree),
137 punct!(")")
138 ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
139 |
140 delimited!(
141 punct!("["),
142 many0!(token_tree),
143 punct!("]")
144 ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
145 |
146 delimited!(
147 punct!("{"),
148 many0!(token_tree),
149 punct!("}")
150 ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
151 ));
152
153 named!(token_tree -> TokenTree, alt!(
154 map!(token, TokenTree::Token)
155 |
156 map!(delimited, TokenTree::Delimited)
157 ));
158
159 named!(token -> Token, alt!(
David Tolnayf7922e32016-10-08 22:16:04 -0700160 keyword!("_") => { |_| Token::Underscore }
David Tolnay59b23c52016-10-02 23:17:55 -0700161 |
David Tolnaye6042a62016-10-08 22:22:10 -0700162 punct!("&&") => { |_| Token::AndAnd } // must be before BinOp
David Tolnay2165b042016-10-08 00:04:23 -0700163 |
David Tolnaye6042a62016-10-08 22:22:10 -0700164 punct!("||") => { |_| Token::OrOr } // must be before BinOp
165 |
166 punct!("->") => { |_| Token::RArrow } // must be before BinOp
167 |
168 punct!("<-") => { |_| Token::LArrow } // must be before Lt
169 |
170 punct!("=>") => { |_| Token::FatArrow } // must be before Eq
171 |
172 punct!("...") => { |_| Token::DotDotDot } // must be before DotDot
173 |
174 punct!("..") => { |_| Token::DotDot } // must be before Dot
175 |
176 punct!(".") => { |_| Token::Dot }
David Tolnay2165b042016-10-08 00:04:23 -0700177 |
David Tolnay84aa0752016-10-02 23:01:13 -0700178 map!(bin_op_eq, Token::BinOpEq)
179 |
180 map!(bin_op, Token::BinOp)
181 |
David Tolnay59b23c52016-10-02 23:17:55 -0700182 map!(lit, Token::Literal)
David Tolnay84aa0752016-10-02 23:01:13 -0700183 |
David Tolnay59b23c52016-10-02 23:17:55 -0700184 map!(ident, Token::Ident)
185 |
186 map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
187 |
188 map!(doc_comment, Token::DocComment)
David Tolnay84aa0752016-10-02 23:01:13 -0700189 |
190 punct!("<=") => { |_| Token::Le }
191 |
192 punct!("==") => { |_| Token::EqEq }
193 |
194 punct!("!=") => { |_| Token::Ne }
195 |
196 punct!(">=") => { |_| Token::Ge }
197 |
David Tolnay84aa0752016-10-02 23:01:13 -0700198 punct!("::") => { |_| Token::ModSep }
199 |
David Tolnay59b23c52016-10-02 23:17:55 -0700200 punct!("=") => { |_| Token::Eq }
201 |
202 punct!("<") => { |_| Token::Lt }
203 |
204 punct!(">") => { |_| Token::Gt }
205 |
206 punct!("!") => { |_| Token::Not }
207 |
208 punct!("~") => { |_| Token::Tilde }
209 |
210 punct!("@") => { |_| Token::At }
211 |
212 punct!(",") => { |_| Token::Comma }
213 |
214 punct!(";") => { |_| Token::Semi }
215 |
216 punct!(":") => { |_| Token::Colon }
217 |
David Tolnay84aa0752016-10-02 23:01:13 -0700218 punct!("#") => { |_| Token::Pound }
219 |
220 punct!("$") => { |_| Token::Dollar }
221 |
222 punct!("?") => { |_| Token::Question }
David Tolnay84aa0752016-10-02 23:01:13 -0700223 ));
224
225 named!(bin_op -> BinOpToken, alt!(
226 punct!("+") => { |_| BinOpToken::Plus }
227 |
228 punct!("-") => { |_| BinOpToken::Minus }
229 |
230 punct!("*") => { |_| BinOpToken::Star }
231 |
232 punct!("/") => { |_| BinOpToken::Slash }
233 |
234 punct!("%") => { |_| BinOpToken::Percent }
235 |
236 punct!("^") => { |_| BinOpToken::Caret }
237 |
238 punct!("&") => { |_| BinOpToken::And }
239 |
240 punct!("|") => { |_| BinOpToken::Or }
241 |
242 punct!("<<") => { |_| BinOpToken::Shl }
243 |
244 punct!(">>") => { |_| BinOpToken::Shr }
245 ));
246
247 named!(bin_op_eq -> BinOpToken, alt!(
248 punct!("+=") => { |_| BinOpToken::Plus }
249 |
250 punct!("-=") => { |_| BinOpToken::Minus }
251 |
252 punct!("*=") => { |_| BinOpToken::Star }
253 |
254 punct!("/=") => { |_| BinOpToken::Slash }
255 |
256 punct!("%=") => { |_| BinOpToken::Percent }
257 |
258 punct!("^=") => { |_| BinOpToken::Caret }
259 |
260 punct!("&=") => { |_| BinOpToken::And }
261 |
262 punct!("|=") => { |_| BinOpToken::Or }
263 |
264 punct!("<<=") => { |_| BinOpToken::Shl }
265 |
266 punct!(">>=") => { |_| BinOpToken::Shr }
267 ));
268
269 named!(doc_comment -> String, alt!(
270 do_parse!(
271 punct!("//!") >>
272 content: take_until!("\n") >>
273 (format!("//!{}", content))
274 )
275 |
276 do_parse!(
277 option!(whitespace) >>
278 peek!(tag!("/*!")) >>
279 com: block_comment >>
280 (com.to_owned())
281 )
282 |
283 do_parse!(
284 punct!("///") >>
285 not!(peek!(tag!("/"))) >>
286 content: take_until!("\n") >>
287 (format!("///{}", content))
288 )
289 |
290 do_parse!(
291 option!(whitespace) >>
292 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
293 com: block_comment >>
294 (com.to_owned())
295 )
296 ));
David Tolnayf4bbbd92016-09-23 14:41:55 -0700297}
David Tolnayf8cf9632016-10-02 23:15:25 -0700298
299#[cfg(feature = "printing")]
300mod printing {
301 use super::*;
302 use quote::{Tokens, ToTokens};
303
304 impl ToTokens for Mac {
305 fn to_tokens(&self, tokens: &mut Tokens) {
306 self.path.to_tokens(tokens);
307 tokens.append("!");
308 for tt in &self.tts {
309 tt.to_tokens(tokens);
310 }
311 }
312 }
313
314 impl ToTokens for TokenTree {
315 fn to_tokens(&self, tokens: &mut Tokens) {
316 match *self {
317 TokenTree::Token(ref token) => token.to_tokens(tokens),
318 TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
319 }
320 }
321 }
322
323 impl DelimToken {
324 fn open(&self) -> &'static str {
325 match *self {
326 DelimToken::Paren => "(",
327 DelimToken::Bracket => "[",
328 DelimToken::Brace => "{",
329 }
330 }
331
332 fn close(&self) -> &'static str {
333 match *self {
334 DelimToken::Paren => ")",
335 DelimToken::Bracket => "]",
336 DelimToken::Brace => "}",
337 }
338 }
339 }
340
341 impl ToTokens for Delimited {
342 fn to_tokens(&self, tokens: &mut Tokens) {
343 tokens.append(self.delim.open());
344 for tt in &self.tts {
345 tt.to_tokens(tokens);
346 }
347 tokens.append(self.delim.close());
348 }
349 }
350
351 impl ToTokens for Token {
352 fn to_tokens(&self, tokens: &mut Tokens) {
353 match *self {
354 Token::Eq => tokens.append("="),
355 Token::Lt => tokens.append("<"),
356 Token::Le => tokens.append("<="),
357 Token::EqEq => tokens.append("=="),
358 Token::Ne => tokens.append("!="),
359 Token::Ge => tokens.append(">="),
360 Token::Gt => tokens.append(">"),
361 Token::AndAnd => tokens.append("&&"),
362 Token::OrOr => tokens.append("||"),
363 Token::Not => tokens.append("!"),
364 Token::Tilde => tokens.append("~"),
365 Token::BinOp(binop) => tokens.append(binop.op()),
366 Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
367 Token::At => tokens.append("@"),
368 Token::Dot => tokens.append("."),
369 Token::DotDot => tokens.append(".."),
370 Token::DotDotDot => tokens.append("..."),
371 Token::Comma => tokens.append(","),
372 Token::Semi => tokens.append(";"),
373 Token::Colon => tokens.append(":"),
374 Token::ModSep => tokens.append("::"),
375 Token::RArrow => tokens.append("->"),
376 Token::LArrow => tokens.append("<-"),
377 Token::FatArrow => tokens.append("=>"),
378 Token::Pound => tokens.append("#"),
379 Token::Dollar => tokens.append("$"),
380 Token::Question => tokens.append("?"),
381 Token::Literal(ref lit) => lit.to_tokens(tokens),
David Tolnay58f6f672016-10-19 08:44:25 -0700382 Token::Ident(ref ident) |
David Tolnayf8cf9632016-10-02 23:15:25 -0700383 Token::Lifetime(ref ident) => ident.to_tokens(tokens),
David Tolnay58f6f672016-10-19 08:44:25 -0700384 Token::Underscore => tokens.append("_"),
David Tolnayf8cf9632016-10-02 23:15:25 -0700385 Token::DocComment(ref com) => {
386 tokens.append(&format!("{}\n", com));
387 }
388 }
389 }
390 }
391
392 impl BinOpToken {
393 fn op(&self) -> &'static str {
394 match *self {
395 BinOpToken::Plus => "+",
396 BinOpToken::Minus => "-",
397 BinOpToken::Star => "*",
398 BinOpToken::Slash => "/",
399 BinOpToken::Percent => "%",
400 BinOpToken::Caret => "^",
401 BinOpToken::And => "&",
402 BinOpToken::Or => "|",
403 BinOpToken::Shl => "<<",
404 BinOpToken::Shr => ">>",
405 }
406 }
407
408 fn assign_op(&self) -> &'static str {
409 match *self {
410 BinOpToken::Plus => "+=",
411 BinOpToken::Minus => "-=",
412 BinOpToken::Star => "*=",
413 BinOpToken::Slash => "/=",
414 BinOpToken::Percent => "%=",
415 BinOpToken::Caret => "^=",
416 BinOpToken::And => "&=",
417 BinOpToken::Or => "|=",
418 BinOpToken::Shl => "<<=",
419 BinOpToken::Shr => ">>=",
420 }
421 }
422 }
423
424 impl ToTokens for BinOpToken {
425 fn to_tokens(&self, tokens: &mut Tokens) {
426 tokens.append(self.op());
427 }
428 }
429}