blob: 26b3c61699f3a9a5bc735d583d02cf4d2c474145 [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.
David Tolnay9bf4af82017-01-07 11:17:46 -08009#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070010pub 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.
David Tolnay9bf4af82017-01-07 11:17:46 -080027#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070028pub 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
David Tolnay9bf4af82017-01-07 11:17:46 -080035#[derive(Debug, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070036pub 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
David Tolnay9bf4af82017-01-07 11:17:46 -080043#[derive(Debug, Clone, Eq, PartialEq, Hash)]
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
David Tolnay9bf4af82017-01-07 11:17:46 -080087#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -070088pub 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
David Tolnay9bf4af82017-01-07 11:17:46 -0800102#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
David Tolnayf4bbbd92016-09-23 14:41:55 -0700103pub 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;
David Tolnay5d55ef72016-12-21 20:20:04 -0500117 use ident::parsing::word;
David Tolnay84aa0752016-10-02 23:01:13 -0700118 use lit::parsing::lit;
David Tolnay5fe14fc2017-01-27 16:22:08 -0800119 use synom::space::{block_comment, whitespace};
David Tolnay5d55ef72016-12-21 20:20:04 -0500120 use ty::parsing::path;
David Tolnay84aa0752016-10-02 23:01:13 -0700121
122 named!(pub mac -> Mac, do_parse!(
David Tolnay5d55ef72016-12-21 20:20:04 -0500123 what: path >>
David Tolnay84aa0752016-10-02 23:01:13 -0700124 punct!("!") >>
125 body: delimited >>
126 (Mac {
David Tolnay5d55ef72016-12-21 20:20:04 -0500127 path: what,
David Tolnay84aa0752016-10-02 23:01:13 -0700128 tts: vec![TokenTree::Delimited(body)],
129 })
130 ));
131
David Tolnayf5fdfa02016-10-23 15:25:17 -0700132 named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
Simon Sapin095a42b2016-10-20 15:54:23 +0200133
David Tolnay84aa0752016-10-02 23:01:13 -0700134 named!(pub delimited -> Delimited, alt!(
135 delimited!(
136 punct!("("),
David Tolnayeea28d62016-10-25 20:44:08 -0700137 token_trees,
David Tolnay84aa0752016-10-02 23:01:13 -0700138 punct!(")")
139 ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
140 |
141 delimited!(
142 punct!("["),
David Tolnayeea28d62016-10-25 20:44:08 -0700143 token_trees,
David Tolnay84aa0752016-10-02 23:01:13 -0700144 punct!("]")
145 ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
146 |
147 delimited!(
148 punct!("{"),
David Tolnayeea28d62016-10-25 20:44:08 -0700149 token_trees,
David Tolnay84aa0752016-10-02 23:01:13 -0700150 punct!("}")
151 ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
152 ));
153
David Tolnay5fe14fc2017-01-27 16:22:08 -0800154 named!(pub token_tree -> TokenTree, alt!(
David Tolnay84aa0752016-10-02 23:01:13 -0700155 map!(token, TokenTree::Token)
156 |
157 map!(delimited, TokenTree::Delimited)
158 ));
159
160 named!(token -> Token, alt!(
David Tolnayf7922e32016-10-08 22:16:04 -0700161 keyword!("_") => { |_| Token::Underscore }
David Tolnay59b23c52016-10-02 23:17:55 -0700162 |
David Tolnaye6042a62016-10-08 22:22:10 -0700163 punct!("&&") => { |_| Token::AndAnd } // must be before BinOp
David Tolnay2165b042016-10-08 00:04:23 -0700164 |
David Tolnaye6042a62016-10-08 22:22:10 -0700165 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 }
David Tolnay2165b042016-10-08 00:04:23 -0700178 |
David Tolnay29833aa2016-10-25 21:08:03 -0700179 map!(doc_comment, Token::DocComment) // must be before bin_op
180 |
181 map!(bin_op_eq, Token::BinOpEq) // must be before bin_op
David Tolnay84aa0752016-10-02 23:01:13 -0700182 |
183 map!(bin_op, Token::BinOp)
184 |
David Tolnay59b23c52016-10-02 23:17:55 -0700185 map!(lit, Token::Literal)
David Tolnay84aa0752016-10-02 23:01:13 -0700186 |
David Tolnay05f462f2016-10-24 22:19:42 -0700187 map!(word, Token::Ident)
David Tolnay59b23c52016-10-02 23:17:55 -0700188 |
189 map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
190 |
David Tolnay84aa0752016-10-02 23:01:13 -0700191 punct!("<=") => { |_| Token::Le }
192 |
193 punct!("==") => { |_| Token::EqEq }
194 |
195 punct!("!=") => { |_| Token::Ne }
196 |
197 punct!(">=") => { |_| Token::Ge }
198 |
David Tolnay84aa0752016-10-02 23:01:13 -0700199 punct!("::") => { |_| Token::ModSep }
200 |
David Tolnay59b23c52016-10-02 23:17:55 -0700201 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 |
David Tolnay84aa0752016-10-02 23:01:13 -0700219 punct!("#") => { |_| Token::Pound }
220 |
221 punct!("$") => { |_| Token::Dollar }
222 |
223 punct!("?") => { |_| Token::Question }
David Tolnay84aa0752016-10-02 23:01:13 -0700224 ));
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!("///") >>
David Tolnay1f16b602017-02-07 20:06:55 -0500286 not!(tag!("/")) >>
David Tolnay84aa0752016-10-02 23:01:13 -0700287 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 ));
David Tolnayf4bbbd92016-09-23 14:41:55 -0700298}
David Tolnayf8cf9632016-10-02 23:15:25 -0700299
300#[cfg(feature = "printing")]
301mod printing {
302 use super::*;
303 use quote::{Tokens, ToTokens};
304
305 impl ToTokens for Mac {
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 {
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 {
325 fn open(&self) -> &'static str {
326 match *self {
327 DelimToken::Paren => "(",
328 DelimToken::Bracket => "[",
329 DelimToken::Brace => "{",
330 }
331 }
332
333 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 {
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 {
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),
David Tolnay58f6f672016-10-19 08:44:25 -0700383 Token::Ident(ref ident) |
David Tolnayf8cf9632016-10-02 23:15:25 -0700384 Token::Lifetime(ref ident) => ident.to_tokens(tokens),
David Tolnay58f6f672016-10-19 08:44:25 -0700385 Token::Underscore => tokens.append("_"),
David Tolnayf8cf9632016-10-02 23:15:25 -0700386 Token::DocComment(ref com) => {
387 tokens.append(&format!("{}\n", com));
388 }
389 }
390 }
391 }
392
393 impl BinOpToken {
394 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
409 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 {
426 fn to_tokens(&self, tokens: &mut Tokens) {
427 tokens.append(self.op());
428 }
429 }
430}