1 use syn::{punctuated::Punctuated, token, Attribute, Ident, Member, Path, Token, Type}; 2 3 ast_enum_of_structs! { 4 /// A pattern in a local binding, function signature, match expression, or 5 /// various other places. 6 /// 7 /// # Syntax tree enum 8 /// 9 /// This type is a [syntax tree enum]. 10 /// 11 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 12 pub enum Pat { 13 /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. 14 Ident(PatIdent), 15 16 /// A path pattern like `Color::Red`. 17 Path(PatPath), 18 19 /// A reference pattern: `&mut var`. 20 Reference(PatReference), 21 22 /// A struct or struct variant pattern: `Variant { x, y, .. }`. 23 Struct(PatStruct), 24 25 /// A tuple pattern: `(a, b)`. 26 Tuple(PatTuple), 27 28 /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. 29 TupleStruct(PatTupleStruct), 30 31 /// A type ascription pattern: `foo: f64`. 32 Type(PatType), 33 34 /// A pattern that matches any value: `_`. 35 Wild(PatWild), 36 37 #[doc(hidden)] 38 __Nonexhaustive, 39 } 40 } 41 42 ast_struct! { 43 /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. 44 pub struct PatIdent { 45 pub attrs: Vec<Attribute>, 46 pub by_ref: Option<Token![ref]>, 47 pub mutability: Option<Token![mut]>, 48 pub ident: Ident, 49 } 50 } 51 52 ast_struct! { 53 /// A path pattern like `Color::Red`. 54 pub struct PatPath { 55 pub attrs: Vec<Attribute>, 56 pub path: Path, 57 } 58 } 59 60 ast_struct! { 61 /// A reference pattern: `&mut var`. 62 pub struct PatReference { 63 pub attrs: Vec<Attribute>, 64 pub and_token: Token![&], 65 pub mutability: Option<Token![mut]>, 66 pub pat: Box<Pat>, 67 } 68 } 69 70 ast_struct! { 71 /// A struct or struct variant pattern: `Variant { x, y, .. }`. 72 pub struct PatStruct { 73 pub attrs: Vec<Attribute>, 74 pub path: Path, 75 pub brace_token: token::Brace, 76 pub fields: Punctuated<FieldPat, Token![,]>, 77 pub dot2_token: Option<Token![..]>, 78 } 79 } 80 81 ast_struct! { 82 /// A tuple pattern: `(a, b)`. 83 pub struct PatTuple { 84 pub attrs: Vec<Attribute>, 85 pub paren_token: token::Paren, 86 pub elems: Punctuated<Pat, Token![,]>, 87 } 88 } 89 90 ast_struct! { 91 /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. 92 pub struct PatTupleStruct { 93 pub attrs: Vec<Attribute>, 94 pub path: Path, 95 pub pat: PatTuple, 96 } 97 } 98 99 ast_struct! { 100 /// A type ascription pattern: `foo: f64`. 101 pub struct PatType { 102 pub attrs: Vec<Attribute>, 103 pub pat: Box<Pat>, 104 pub colon_token: Token![:], 105 pub ty: Box<Type>, 106 } 107 } 108 109 ast_struct! { 110 /// A pattern that matches any value: `_`. 111 pub struct PatWild { 112 pub attrs: Vec<Attribute>, 113 pub underscore_token: Token![_], 114 } 115 } 116 117 ast_struct! { 118 /// A single field in a struct pattern. 119 /// 120 /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated 121 /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token. 122 pub struct FieldPat { 123 pub attrs: Vec<Attribute>, 124 pub member: Member, 125 pub colon_token: Option<Token![:]>, 126 pub pat: Box<Pat>, 127 } 128 } 129 130 mod parsing { 131 use syn::{ 132 braced, 133 ext::IdentExt, 134 parenthesized, 135 parse::{Parse, ParseStream, Result}, 136 punctuated::Punctuated, 137 token, Ident, Member, Path, Token, 138 }; 139 140 use crate::path; 141 142 use super::{ 143 FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct, 144 PatWild, 145 }; 146 147 impl Parse for Pat { parse(input: ParseStream<'_>) -> Result<Self>148 fn parse(input: ParseStream<'_>) -> Result<Self> { 149 let lookahead = input.lookahead1(); 150 if lookahead.peek(Ident) 151 && ({ 152 input.peek2(Token![::]) 153 || input.peek2(token::Brace) 154 || input.peek2(token::Paren) 155 }) 156 || input.peek(Token![self]) && input.peek2(Token![::]) 157 || lookahead.peek(Token![::]) 158 || lookahead.peek(Token![<]) 159 || input.peek(Token![Self]) 160 || input.peek(Token![super]) 161 || input.peek(Token![extern]) 162 || input.peek(Token![crate]) 163 { 164 pat_path_or_struct(input) 165 } else if lookahead.peek(Token![_]) { 166 input.call(pat_wild).map(Pat::Wild) 167 } else if lookahead.peek(Token![ref]) 168 || lookahead.peek(Token![mut]) 169 || input.peek(Token![self]) 170 || input.peek(Ident) 171 { 172 input.call(pat_ident).map(Pat::Ident) 173 } else if lookahead.peek(Token![&]) { 174 input.call(pat_reference).map(Pat::Reference) 175 } else if lookahead.peek(token::Paren) { 176 input.call(pat_tuple).map(Pat::Tuple) 177 } else { 178 Err(lookahead.error()) 179 } 180 } 181 } 182 pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat>183 fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> { 184 let path = path::parse_path(input)?; 185 186 if input.peek(token::Brace) { 187 pat_struct(input, path).map(Pat::Struct) 188 } else if input.peek(token::Paren) { 189 pat_tuple_struct(input, path).map(Pat::TupleStruct) 190 } else { 191 Ok(Pat::Path(PatPath { attrs: Vec::new(), path })) 192 } 193 } 194 pat_wild(input: ParseStream<'_>) -> Result<PatWild>195 fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> { 196 Ok(PatWild { attrs: Vec::new(), underscore_token: input.parse()? }) 197 } 198 pat_ident(input: ParseStream<'_>) -> Result<PatIdent>199 fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> { 200 Ok(PatIdent { 201 attrs: Vec::new(), 202 by_ref: input.parse()?, 203 mutability: input.parse()?, 204 ident: input.call(Ident::parse_any)?, 205 }) 206 } 207 pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct>208 fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> { 209 Ok(PatTupleStruct { attrs: Vec::new(), path, pat: input.call(pat_tuple)? }) 210 } 211 pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct>212 fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> { 213 let content; 214 let brace_token = braced!(content in input); 215 216 let mut fields = Punctuated::new(); 217 while !content.is_empty() && !content.peek(Token![..]) { 218 let value = content.call(field_pat)?; 219 fields.push_value(value); 220 if !content.peek(Token![,]) { 221 break; 222 } 223 let punct: Token![,] = content.parse()?; 224 fields.push_punct(punct); 225 } 226 227 let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) { 228 Some(content.parse()?) 229 } else { 230 None 231 }; 232 233 Ok(PatStruct { attrs: Vec::new(), path, brace_token, fields, dot2_token }) 234 } 235 field_pat(input: ParseStream<'_>) -> Result<FieldPat>236 fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> { 237 let boxed: Option<Token![box]> = input.parse()?; 238 let by_ref: Option<Token![ref]> = input.parse()?; 239 let mutability: Option<Token![mut]> = input.parse()?; 240 let member: Member = input.parse()?; 241 242 if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) 243 || is_unnamed(&member) 244 { 245 return Ok(FieldPat { 246 attrs: Vec::new(), 247 member, 248 colon_token: input.parse()?, 249 pat: input.parse()?, 250 }); 251 } 252 253 let ident = match member { 254 Member::Named(ident) => ident, 255 Member::Unnamed(_) => unreachable!(), 256 }; 257 258 let pat = 259 Pat::Ident(PatIdent { attrs: Vec::new(), by_ref, mutability, ident: ident.clone() }); 260 261 Ok(FieldPat { 262 member: Member::Named(ident), 263 pat: Box::new(pat), 264 attrs: Vec::new(), 265 colon_token: None, 266 }) 267 } 268 pat_tuple(input: ParseStream<'_>) -> Result<PatTuple>269 fn pat_tuple(input: ParseStream<'_>) -> Result<PatTuple> { 270 let content; 271 let paren_token = parenthesized!(content in input); 272 273 let mut elems = Punctuated::new(); 274 while !content.is_empty() { 275 let value: Pat = content.parse()?; 276 elems.push_value(value); 277 if content.is_empty() { 278 break; 279 } 280 let punct = content.parse()?; 281 elems.push_punct(punct); 282 } 283 284 Ok(PatTuple { attrs: Vec::new(), paren_token, elems }) 285 } 286 pat_reference(input: ParseStream<'_>) -> Result<PatReference>287 fn pat_reference(input: ParseStream<'_>) -> Result<PatReference> { 288 Ok(PatReference { 289 attrs: Vec::new(), 290 and_token: input.parse()?, 291 mutability: input.parse()?, 292 pat: input.parse()?, 293 }) 294 } 295 is_unnamed(member: &Member) -> bool296 fn is_unnamed(member: &Member) -> bool { 297 match member { 298 Member::Named(_) => false, 299 Member::Unnamed(_) => true, 300 } 301 } 302 } 303 304 mod printing { 305 use proc_macro2::TokenStream; 306 use quote::{ToTokens, TokenStreamExt}; 307 use syn::Token; 308 309 use super::{ 310 FieldPat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType, 311 PatWild, 312 }; 313 314 impl ToTokens for PatWild { to_tokens(&self, tokens: &mut TokenStream)315 fn to_tokens(&self, tokens: &mut TokenStream) { 316 self.underscore_token.to_tokens(tokens); 317 } 318 } 319 320 impl ToTokens for PatIdent { to_tokens(&self, tokens: &mut TokenStream)321 fn to_tokens(&self, tokens: &mut TokenStream) { 322 self.by_ref.to_tokens(tokens); 323 self.mutability.to_tokens(tokens); 324 self.ident.to_tokens(tokens); 325 } 326 } 327 328 impl ToTokens for PatStruct { to_tokens(&self, tokens: &mut TokenStream)329 fn to_tokens(&self, tokens: &mut TokenStream) { 330 self.path.to_tokens(tokens); 331 self.brace_token.surround(tokens, |tokens| { 332 self.fields.to_tokens(tokens); 333 // NOTE: We need a comma before the dot2 token if it is present. 334 if !self.fields.empty_or_trailing() && self.dot2_token.is_some() { 335 <Token![,]>::default().to_tokens(tokens); 336 } 337 self.dot2_token.to_tokens(tokens); 338 }); 339 } 340 } 341 342 impl ToTokens for PatTupleStruct { to_tokens(&self, tokens: &mut TokenStream)343 fn to_tokens(&self, tokens: &mut TokenStream) { 344 self.path.to_tokens(tokens); 345 self.pat.to_tokens(tokens); 346 } 347 } 348 349 impl ToTokens for PatType { to_tokens(&self, tokens: &mut TokenStream)350 fn to_tokens(&self, tokens: &mut TokenStream) { 351 tokens.append_all(&self.attrs); 352 self.pat.to_tokens(tokens); 353 self.colon_token.to_tokens(tokens); 354 self.ty.to_tokens(tokens); 355 } 356 } 357 358 impl ToTokens for PatPath { to_tokens(&self, tokens: &mut TokenStream)359 fn to_tokens(&self, tokens: &mut TokenStream) { 360 self.path.to_tokens(tokens) 361 } 362 } 363 364 impl ToTokens for PatTuple { to_tokens(&self, tokens: &mut TokenStream)365 fn to_tokens(&self, tokens: &mut TokenStream) { 366 self.paren_token.surround(tokens, |tokens| { 367 self.elems.to_tokens(tokens); 368 }); 369 } 370 } 371 372 impl ToTokens for PatReference { to_tokens(&self, tokens: &mut TokenStream)373 fn to_tokens(&self, tokens: &mut TokenStream) { 374 self.and_token.to_tokens(tokens); 375 self.mutability.to_tokens(tokens); 376 self.pat.to_tokens(tokens); 377 } 378 } 379 380 impl ToTokens for FieldPat { to_tokens(&self, tokens: &mut TokenStream)381 fn to_tokens(&self, tokens: &mut TokenStream) { 382 if let Some(colon_token) = &self.colon_token { 383 self.member.to_tokens(tokens); 384 colon_token.to_tokens(tokens); 385 } 386 self.pat.to_tokens(tokens); 387 } 388 } 389 } 390