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