blob: 56d26f846be2e08795f1462e1abaa29a5c496e63 [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
Simon Sapin095a42b2016-10-20 15:54:23 +0200131 named!(pub token_trees -> Vec<TokenTree>, do_parse!(
132 tts: many0!(token_tree) >>
133 option!(whitespace) >>
134 (tts)
135 ));
136
David Tolnay84aa0752016-10-02 23:01:13 -0700137 named!(pub delimited -> Delimited, alt!(
138 delimited!(
139 punct!("("),
140 many0!(token_tree),
141 punct!(")")
142 ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
143 |
144 delimited!(
145 punct!("["),
146 many0!(token_tree),
147 punct!("]")
148 ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
149 |
150 delimited!(
151 punct!("{"),
152 many0!(token_tree),
153 punct!("}")
154 ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
155 ));
156
157 named!(token_tree -> TokenTree, alt!(
158 map!(token, TokenTree::Token)
159 |
160 map!(delimited, TokenTree::Delimited)
161 ));
162
163 named!(token -> Token, alt!(
David Tolnayf7922e32016-10-08 22:16:04 -0700164 keyword!("_") => { |_| Token::Underscore }
David Tolnay59b23c52016-10-02 23:17:55 -0700165 |
David Tolnaye6042a62016-10-08 22:22:10 -0700166 punct!("&&") => { |_| Token::AndAnd } // must be before BinOp
David Tolnay2165b042016-10-08 00:04:23 -0700167 |
David Tolnaye6042a62016-10-08 22:22:10 -0700168 punct!("||") => { |_| Token::OrOr } // must be before BinOp
169 |
170 punct!("->") => { |_| Token::RArrow } // must be before BinOp
171 |
172 punct!("<-") => { |_| Token::LArrow } // must be before Lt
173 |
174 punct!("=>") => { |_| Token::FatArrow } // must be before Eq
175 |
176 punct!("...") => { |_| Token::DotDotDot } // must be before DotDot
177 |
178 punct!("..") => { |_| Token::DotDot } // must be before Dot
179 |
180 punct!(".") => { |_| Token::Dot }
David Tolnay2165b042016-10-08 00:04:23 -0700181 |
David Tolnay84aa0752016-10-02 23:01:13 -0700182 map!(bin_op_eq, Token::BinOpEq)
183 |
184 map!(bin_op, Token::BinOp)
185 |
David Tolnay59b23c52016-10-02 23:17:55 -0700186 map!(lit, Token::Literal)
David Tolnay84aa0752016-10-02 23:01:13 -0700187 |
David Tolnay59b23c52016-10-02 23:17:55 -0700188 map!(ident, Token::Ident)
189 |
190 map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
191 |
192 map!(doc_comment, Token::DocComment)
David Tolnay84aa0752016-10-02 23:01:13 -0700193 |
194 punct!("<=") => { |_| Token::Le }
195 |
196 punct!("==") => { |_| Token::EqEq }
197 |
198 punct!("!=") => { |_| Token::Ne }
199 |
200 punct!(">=") => { |_| Token::Ge }
201 |
David Tolnay84aa0752016-10-02 23:01:13 -0700202 punct!("::") => { |_| Token::ModSep }
203 |
David Tolnay59b23c52016-10-02 23:17:55 -0700204 punct!("=") => { |_| Token::Eq }
205 |
206 punct!("<") => { |_| Token::Lt }
207 |
208 punct!(">") => { |_| Token::Gt }
209 |
210 punct!("!") => { |_| Token::Not }
211 |
212 punct!("~") => { |_| Token::Tilde }
213 |
214 punct!("@") => { |_| Token::At }
215 |
216 punct!(",") => { |_| Token::Comma }
217 |
218 punct!(";") => { |_| Token::Semi }
219 |
220 punct!(":") => { |_| Token::Colon }
221 |
David Tolnay84aa0752016-10-02 23:01:13 -0700222 punct!("#") => { |_| Token::Pound }
223 |
224 punct!("$") => { |_| Token::Dollar }
225 |
226 punct!("?") => { |_| Token::Question }
David Tolnay84aa0752016-10-02 23:01:13 -0700227 ));
228
229 named!(bin_op -> BinOpToken, alt!(
230 punct!("+") => { |_| BinOpToken::Plus }
231 |
232 punct!("-") => { |_| BinOpToken::Minus }
233 |
234 punct!("*") => { |_| BinOpToken::Star }
235 |
236 punct!("/") => { |_| BinOpToken::Slash }
237 |
238 punct!("%") => { |_| BinOpToken::Percent }
239 |
240 punct!("^") => { |_| BinOpToken::Caret }
241 |
242 punct!("&") => { |_| BinOpToken::And }
243 |
244 punct!("|") => { |_| BinOpToken::Or }
245 |
246 punct!("<<") => { |_| BinOpToken::Shl }
247 |
248 punct!(">>") => { |_| BinOpToken::Shr }
249 ));
250
251 named!(bin_op_eq -> BinOpToken, alt!(
252 punct!("+=") => { |_| BinOpToken::Plus }
253 |
254 punct!("-=") => { |_| BinOpToken::Minus }
255 |
256 punct!("*=") => { |_| BinOpToken::Star }
257 |
258 punct!("/=") => { |_| BinOpToken::Slash }
259 |
260 punct!("%=") => { |_| BinOpToken::Percent }
261 |
262 punct!("^=") => { |_| BinOpToken::Caret }
263 |
264 punct!("&=") => { |_| BinOpToken::And }
265 |
266 punct!("|=") => { |_| BinOpToken::Or }
267 |
268 punct!("<<=") => { |_| BinOpToken::Shl }
269 |
270 punct!(">>=") => { |_| BinOpToken::Shr }
271 ));
272
273 named!(doc_comment -> String, alt!(
274 do_parse!(
275 punct!("//!") >>
276 content: take_until!("\n") >>
277 (format!("//!{}", content))
278 )
279 |
280 do_parse!(
281 option!(whitespace) >>
282 peek!(tag!("/*!")) >>
283 com: block_comment >>
284 (com.to_owned())
285 )
286 |
287 do_parse!(
288 punct!("///") >>
289 not!(peek!(tag!("/"))) >>
290 content: take_until!("\n") >>
291 (format!("///{}", content))
292 )
293 |
294 do_parse!(
295 option!(whitespace) >>
296 peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
297 com: block_comment >>
298 (com.to_owned())
299 )
300 ));
David Tolnayf4bbbd92016-09-23 14:41:55 -0700301}
David Tolnayf8cf9632016-10-02 23:15:25 -0700302
303#[cfg(feature = "printing")]
304mod printing {
305 use super::*;
306 use quote::{Tokens, ToTokens};
307
308 impl ToTokens for Mac {
309 fn to_tokens(&self, tokens: &mut Tokens) {
310 self.path.to_tokens(tokens);
311 tokens.append("!");
312 for tt in &self.tts {
313 tt.to_tokens(tokens);
314 }
315 }
316 }
317
318 impl ToTokens for TokenTree {
319 fn to_tokens(&self, tokens: &mut Tokens) {
320 match *self {
321 TokenTree::Token(ref token) => token.to_tokens(tokens),
322 TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
323 }
324 }
325 }
326
327 impl DelimToken {
328 fn open(&self) -> &'static str {
329 match *self {
330 DelimToken::Paren => "(",
331 DelimToken::Bracket => "[",
332 DelimToken::Brace => "{",
333 }
334 }
335
336 fn close(&self) -> &'static str {
337 match *self {
338 DelimToken::Paren => ")",
339 DelimToken::Bracket => "]",
340 DelimToken::Brace => "}",
341 }
342 }
343 }
344
345 impl ToTokens for Delimited {
346 fn to_tokens(&self, tokens: &mut Tokens) {
347 tokens.append(self.delim.open());
348 for tt in &self.tts {
349 tt.to_tokens(tokens);
350 }
351 tokens.append(self.delim.close());
352 }
353 }
354
355 impl ToTokens for Token {
356 fn to_tokens(&self, tokens: &mut Tokens) {
357 match *self {
358 Token::Eq => tokens.append("="),
359 Token::Lt => tokens.append("<"),
360 Token::Le => tokens.append("<="),
361 Token::EqEq => tokens.append("=="),
362 Token::Ne => tokens.append("!="),
363 Token::Ge => tokens.append(">="),
364 Token::Gt => tokens.append(">"),
365 Token::AndAnd => tokens.append("&&"),
366 Token::OrOr => tokens.append("||"),
367 Token::Not => tokens.append("!"),
368 Token::Tilde => tokens.append("~"),
369 Token::BinOp(binop) => tokens.append(binop.op()),
370 Token::BinOpEq(binop) => tokens.append(binop.assign_op()),
371 Token::At => tokens.append("@"),
372 Token::Dot => tokens.append("."),
373 Token::DotDot => tokens.append(".."),
374 Token::DotDotDot => tokens.append("..."),
375 Token::Comma => tokens.append(","),
376 Token::Semi => tokens.append(";"),
377 Token::Colon => tokens.append(":"),
378 Token::ModSep => tokens.append("::"),
379 Token::RArrow => tokens.append("->"),
380 Token::LArrow => tokens.append("<-"),
381 Token::FatArrow => tokens.append("=>"),
382 Token::Pound => tokens.append("#"),
383 Token::Dollar => tokens.append("$"),
384 Token::Question => tokens.append("?"),
385 Token::Literal(ref lit) => lit.to_tokens(tokens),
David Tolnay58f6f672016-10-19 08:44:25 -0700386 Token::Ident(ref ident) |
David Tolnayf8cf9632016-10-02 23:15:25 -0700387 Token::Lifetime(ref ident) => ident.to_tokens(tokens),
David Tolnay58f6f672016-10-19 08:44:25 -0700388 Token::Underscore => tokens.append("_"),
David Tolnayf8cf9632016-10-02 23:15:25 -0700389 Token::DocComment(ref com) => {
390 tokens.append(&format!("{}\n", com));
391 }
392 }
393 }
394 }
395
396 impl BinOpToken {
397 fn op(&self) -> &'static str {
398 match *self {
399 BinOpToken::Plus => "+",
400 BinOpToken::Minus => "-",
401 BinOpToken::Star => "*",
402 BinOpToken::Slash => "/",
403 BinOpToken::Percent => "%",
404 BinOpToken::Caret => "^",
405 BinOpToken::And => "&",
406 BinOpToken::Or => "|",
407 BinOpToken::Shl => "<<",
408 BinOpToken::Shr => ">>",
409 }
410 }
411
412 fn assign_op(&self) -> &'static str {
413 match *self {
414 BinOpToken::Plus => "+=",
415 BinOpToken::Minus => "-=",
416 BinOpToken::Star => "*=",
417 BinOpToken::Slash => "/=",
418 BinOpToken::Percent => "%=",
419 BinOpToken::Caret => "^=",
420 BinOpToken::And => "&=",
421 BinOpToken::Or => "|=",
422 BinOpToken::Shl => "<<=",
423 BinOpToken::Shr => ">>=",
424 }
425 }
426 }
427
428 impl ToTokens for BinOpToken {
429 fn to_tokens(&self, tokens: &mut Tokens) {
430 tokens.append(self.op());
431 }
432 }
433}