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