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]: https://docs.rs/syn/1/syn/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, Attribute, Ident, Member, Path, Token, 138 }; 139 140 use super::{ 141 FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct, 142 PatWild, 143 }; 144 use crate::path; 145 146 impl Parse for Pat { parse(input: ParseStream<'_>) -> Result<Self>147 fn parse(input: ParseStream<'_>) -> Result<Self> { 148 let lookahead = input.lookahead1(); 149 if { 150 let ahead = input.fork(); 151 ahead.parse::<Option<Ident>>()?.is_some() 152 && (ahead.peek(Token![::]) 153 || ahead.peek(token::Brace) 154 || ahead.peek(token::Paren)) 155 } || { 156 let ahead = input.fork(); 157 ahead.parse::<Option<Token![self]>>()?.is_some() && ahead.peek(Token![::]) 158 } || lookahead.peek(Token![::]) 159 || lookahead.peek(Token![<]) 160 || input.peek(Token![Self]) 161 || input.peek(Token![super]) 162 || input.peek(Token![extern]) 163 || input.peek(Token![crate]) 164 { 165 pat_path_or_struct(input) 166 } else if lookahead.peek(Token![_]) { 167 input.call(pat_wild).map(Pat::Wild) 168 } else if lookahead.peek(Token![ref]) 169 || lookahead.peek(Token![mut]) 170 || input.peek(Token![self]) 171 || input.peek(Ident) 172 { 173 input.call(pat_ident).map(Pat::Ident) 174 } else if lookahead.peek(Token![&]) { 175 input.call(pat_reference).map(Pat::Reference) 176 } else if lookahead.peek(token::Paren) { 177 input.call(pat_tuple).map(Pat::Tuple) 178 } else { 179 Err(lookahead.error()) 180 } 181 } 182 } 183 pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat>184 fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> { 185 let path = path::parse_path(input)?; 186 187 if input.peek(token::Brace) { 188 pat_struct(input, path).map(Pat::Struct) 189 } else if input.peek(token::Paren) { 190 pat_tuple_struct(input, path).map(Pat::TupleStruct) 191 } else { 192 Ok(Pat::Path(PatPath { attrs: Vec::new(), path })) 193 } 194 } 195 pat_wild(input: ParseStream<'_>) -> Result<PatWild>196 fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> { 197 Ok(PatWild { attrs: Vec::new(), underscore_token: input.parse()? }) 198 } 199 pat_ident(input: ParseStream<'_>) -> Result<PatIdent>200 fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> { 201 Ok(PatIdent { 202 attrs: Vec::new(), 203 by_ref: input.parse()?, 204 mutability: input.parse()?, 205 ident: input.call(Ident::parse_any)?, 206 }) 207 } 208 pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct>209 fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> { 210 Ok(PatTupleStruct { attrs: Vec::new(), path, pat: input.call(pat_tuple)? }) 211 } 212 pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct>213 fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> { 214 let content; 215 let brace_token = braced!(content in input); 216 217 let mut fields = Punctuated::new(); 218 while !content.is_empty() && !content.peek(Token![..]) { 219 let value = content.call(field_pat)?; 220 fields.push_value(value); 221 if content.is_empty() { 222 break; 223 } 224 let punct: Token![,] = content.parse()?; 225 fields.push_punct(punct); 226 } 227 228 let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) { 229 Some(content.parse()?) 230 } else { 231 None 232 }; 233 234 Ok(PatStruct { attrs: Vec::new(), path, brace_token, fields, dot2_token }) 235 } 236 field_pat(input: ParseStream<'_>) -> Result<FieldPat>237 fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> { 238 let attrs = input.call(Attribute::parse_outer)?; 239 let boxed: Option<Token![box]> = input.parse()?; 240 let by_ref: Option<Token![ref]> = input.parse()?; 241 let mutability: Option<Token![mut]> = input.parse()?; 242 let member: Member = input.parse()?; 243 244 if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) 245 || is_unnamed(&member) 246 { 247 return Ok(FieldPat { 248 attrs, 249 member, 250 colon_token: input.parse()?, 251 pat: input.parse()?, 252 }); 253 } 254 255 let ident = match member { 256 Member::Named(ident) => ident, 257 Member::Unnamed(_) => unreachable!(), 258 }; 259 260 let pat = 261 Pat::Ident(PatIdent { attrs: Vec::new(), by_ref, mutability, ident: ident.clone() }); 262 263 Ok(FieldPat { attrs, member: Member::Named(ident), colon_token: None, pat: Box::new(pat) }) 264 } 265 pat_tuple(input: ParseStream<'_>) -> Result<PatTuple>266 fn pat_tuple(input: ParseStream<'_>) -> Result<PatTuple> { 267 let content; 268 let paren_token = parenthesized!(content in input); 269 270 let mut elems = Punctuated::new(); 271 while !content.is_empty() { 272 let value: Pat = content.parse()?; 273 elems.push_value(value); 274 if content.is_empty() { 275 break; 276 } 277 let punct = content.parse()?; 278 elems.push_punct(punct); 279 } 280 281 Ok(PatTuple { attrs: Vec::new(), paren_token, elems }) 282 } 283 pat_reference(input: ParseStream<'_>) -> Result<PatReference>284 fn pat_reference(input: ParseStream<'_>) -> Result<PatReference> { 285 Ok(PatReference { 286 attrs: Vec::new(), 287 and_token: input.parse()?, 288 mutability: input.parse()?, 289 pat: input.parse()?, 290 }) 291 } 292 is_unnamed(member: &Member) -> bool293 fn is_unnamed(member: &Member) -> bool { 294 match member { 295 Member::Named(_) => false, 296 Member::Unnamed(_) => true, 297 } 298 } 299 } 300 301 mod printing { 302 use proc_macro2::TokenStream; 303 use quote::{ToTokens, TokenStreamExt}; 304 use syn::Token; 305 306 use super::{ 307 FieldPat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType, 308 PatWild, 309 }; 310 311 impl ToTokens for PatWild { to_tokens(&self, tokens: &mut TokenStream)312 fn to_tokens(&self, tokens: &mut TokenStream) { 313 self.underscore_token.to_tokens(tokens); 314 } 315 } 316 317 impl ToTokens for PatIdent { to_tokens(&self, tokens: &mut TokenStream)318 fn to_tokens(&self, tokens: &mut TokenStream) { 319 self.by_ref.to_tokens(tokens); 320 self.mutability.to_tokens(tokens); 321 self.ident.to_tokens(tokens); 322 } 323 } 324 325 impl ToTokens for PatStruct { to_tokens(&self, tokens: &mut TokenStream)326 fn to_tokens(&self, tokens: &mut TokenStream) { 327 self.path.to_tokens(tokens); 328 self.brace_token.surround(tokens, |tokens| { 329 self.fields.to_tokens(tokens); 330 // NOTE: We need a comma before the dot2 token if it is present. 331 if !self.fields.empty_or_trailing() && self.dot2_token.is_some() { 332 <Token![,]>::default().to_tokens(tokens); 333 } 334 self.dot2_token.to_tokens(tokens); 335 }); 336 } 337 } 338 339 impl ToTokens for PatTupleStruct { to_tokens(&self, tokens: &mut TokenStream)340 fn to_tokens(&self, tokens: &mut TokenStream) { 341 self.path.to_tokens(tokens); 342 self.pat.to_tokens(tokens); 343 } 344 } 345 346 impl ToTokens for PatType { to_tokens(&self, tokens: &mut TokenStream)347 fn to_tokens(&self, tokens: &mut TokenStream) { 348 tokens.append_all(&self.attrs); 349 self.pat.to_tokens(tokens); 350 self.colon_token.to_tokens(tokens); 351 self.ty.to_tokens(tokens); 352 } 353 } 354 355 impl ToTokens for PatPath { to_tokens(&self, tokens: &mut TokenStream)356 fn to_tokens(&self, tokens: &mut TokenStream) { 357 self.path.to_tokens(tokens) 358 } 359 } 360 361 impl ToTokens for PatTuple { to_tokens(&self, tokens: &mut TokenStream)362 fn to_tokens(&self, tokens: &mut TokenStream) { 363 self.paren_token.surround(tokens, |tokens| { 364 self.elems.to_tokens(tokens); 365 }); 366 } 367 } 368 369 impl ToTokens for PatReference { to_tokens(&self, tokens: &mut TokenStream)370 fn to_tokens(&self, tokens: &mut TokenStream) { 371 self.and_token.to_tokens(tokens); 372 self.mutability.to_tokens(tokens); 373 self.pat.to_tokens(tokens); 374 } 375 } 376 377 impl ToTokens for FieldPat { to_tokens(&self, tokens: &mut TokenStream)378 fn to_tokens(&self, tokens: &mut TokenStream) { 379 if let Some(colon_token) = &self.colon_token { 380 self.member.to_tokens(tokens); 381 colon_token.to_tokens(tokens); 382 } 383 self.pat.to_tokens(tokens); 384 } 385 } 386 } 387