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