1use syn::{punctuated::Punctuated, token, Attribute, Ident, Member, Path, Token, Type};
6
7use super::PatPath;
8
9ast_enum_of_structs! {
10 #[non_exhaustive]
13 pub enum Pat {
14 Ident(PatIdent),
16
17 Path(PatPath),
19
20 Reference(PatReference),
22
23 Struct(PatStruct),
25
26 Tuple(PatTuple),
28
29 TupleStruct(PatTupleStruct),
31
32 Type(PatType),
34
35 Wild(PatWild),
37 }
38}
39
40ast_struct! {
41 pub struct PatIdent {
43 pub attrs: Vec<Attribute>,
44 pub by_ref: Option<Token![ref]>,
45 pub mutability: Option<Token![mut]>,
46 pub ident: Ident,
47 }
48}
49
50ast_struct! {
51 pub struct PatReference {
53 pub attrs: Vec<Attribute>,
54 pub and_token: Token![&],
55 pub mutability: Option<Token![mut]>,
56 pub pat: Box<Pat>,
57 }
58}
59
60ast_struct! {
61 pub struct PatRest {
63 pub attrs: Vec<Attribute>,
64 pub dot2_token: Token![..],
65 }
66}
67
68ast_struct! {
69 pub struct PatStruct {
71 pub attrs: Vec<Attribute>,
72 pub path: Path,
73 pub brace_token: token::Brace,
74 pub fields: Punctuated<FieldPat, Token![,]>,
75 pub rest: Option<PatRest>,
76 }
77}
78
79ast_struct! {
80 pub struct PatTuple {
82 pub attrs: Vec<Attribute>,
83 pub paren_token: token::Paren,
84 pub elems: Punctuated<Pat, Token![,]>,
85 }
86}
87
88ast_struct! {
89 pub struct PatTupleStruct {
91 pub attrs: Vec<Attribute>,
92 pub path: Path,
93 pub paren_token: token::Paren,
94 pub elems: Punctuated<Pat, Token![,]>,
95 }
96}
97
98ast_struct! {
99 pub struct PatType {
101 pub attrs: Vec<Attribute>,
102 pub pat: Box<Pat>,
103 pub colon_token: Token![:],
104 pub ty: Box<Type>,
105 }
106}
107
108ast_struct! {
109 pub struct PatWild {
111 pub attrs: Vec<Attribute>,
112 pub underscore_token: Token![_],
113 }
114}
115
116ast_struct! {
117 pub struct FieldPat {
122 pub attrs: Vec<Attribute>,
123 pub member: Member,
124 pub colon_token: Option<Token![:]>,
125 pub pat: Box<Pat>,
126 }
127}
128
129mod parsing {
130 use syn::{
131 braced,
132 ext::IdentExt,
133 parenthesized,
134 parse::{ParseStream, Result},
135 punctuated::Punctuated,
136 token, Attribute, ExprPath, Ident, Member, Path, Token,
137 };
138
139 use super::{
140 FieldPat, Pat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct,
141 PatWild,
142 };
143 use crate::path;
144
145 impl Pat {
146 pub fn parse_single(input: ParseStream<'_>) -> Result<Self> {
148 let lookahead = input.lookahead1();
149 if lookahead.peek(Ident)
150 && (input.peek2(Token![::])
151 || input.peek2(Token![!])
152 || input.peek2(token::Brace)
153 || input.peek2(token::Paren)
154 || input.peek2(Token![..]))
155 || input.peek(Token![self]) && input.peek2(Token![::])
156 || lookahead.peek(Token![::])
157 || lookahead.peek(Token![<])
158 || input.peek(Token![Self])
159 || input.peek(Token![super])
160 || input.peek(Token![crate])
161 {
162 pat_path_or_struct(input)
163 } else if lookahead.peek(Token![_]) {
164 input.call(pat_wild).map(Pat::Wild)
165 } else if lookahead.peek(Token![ref])
166 || lookahead.peek(Token![mut])
167 || input.peek(Token![self])
168 || input.peek(Ident)
169 {
170 input.call(pat_ident).map(Pat::Ident)
171 } else if lookahead.peek(Token![&]) {
172 input.call(pat_reference).map(Pat::Reference)
173 } else if lookahead.peek(token::Paren) {
174 input.call(pat_paren_or_tuple)
175 } else {
176 Err(lookahead.error())
177 }
178 }
179 }
180
181 fn pat_path_or_struct(input: ParseStream<'_>) -> Result<Pat> {
182 let path = path::parse_path(input)?;
183
184 if input.peek(token::Brace) {
185 pat_struct(input, path).map(Pat::Struct)
186 } else if input.peek(token::Paren) {
187 pat_tuple_struct(input, path).map(Pat::TupleStruct)
188 } else {
189 Ok(Pat::Path(ExprPath { attrs: Vec::new(), qself: None, path }))
190 }
191 }
192
193 fn pat_wild(input: ParseStream<'_>) -> Result<PatWild> {
194 Ok(PatWild { attrs: Vec::new(), underscore_token: input.parse()? })
195 }
196
197 fn pat_ident(input: ParseStream<'_>) -> Result<PatIdent> {
198 Ok(PatIdent {
199 attrs: Vec::new(),
200 by_ref: input.parse()?,
201 mutability: input.parse()?,
202 ident: input.call(Ident::parse_any)?,
203 })
204 }
205
206 fn pat_tuple_struct(input: ParseStream<'_>, path: Path) -> Result<PatTupleStruct> {
207 let content;
208 let paren_token = parenthesized!(content in input);
209
210 let mut elems = Punctuated::new();
211 while !content.is_empty() {
212 let value = Pat::parse_single(&content)?;
213 elems.push_value(value);
214 if content.is_empty() {
215 break;
216 }
217 let punct = content.parse()?;
218 elems.push_punct(punct);
219 }
220
221 Ok(PatTupleStruct { attrs: Vec::new(), path, paren_token, elems })
222 }
223
224 fn pat_struct(input: ParseStream<'_>, path: Path) -> Result<PatStruct> {
225 let content;
226 let brace_token = braced!(content in input);
227
228 let mut fields = Punctuated::new();
229 let mut rest = None;
230 while !content.is_empty() {
231 let attrs = content.call(Attribute::parse_outer)?;
232 if content.peek(Token![..]) {
233 rest = Some(PatRest { attrs, dot2_token: content.parse()? });
234 break;
235 }
236 let mut value = content.call(field_pat)?;
237 value.attrs = attrs;
238 fields.push_value(value);
239 if content.is_empty() {
240 break;
241 }
242 let punct: Token![,] = content.parse()?;
243 fields.push_punct(punct);
244 }
245
246 Ok(PatStruct { attrs: Vec::new(), path, brace_token, fields, rest })
247 }
248
249 fn field_pat(input: ParseStream<'_>) -> Result<FieldPat> {
250 let boxed: Option<Token![box]> = input.parse()?;
251 let by_ref: Option<Token![ref]> = input.parse()?;
252 let mutability: Option<Token![mut]> = input.parse()?;
253
254 let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() {
255 input.parse().map(Member::Named)
256 } else {
257 input.parse()
258 }?;
259
260 if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:])
261 || is_unnamed(&member)
262 {
263 return Ok(FieldPat {
264 attrs: Vec::new(),
265 member,
266 colon_token: Some(input.parse()?),
267 pat: Box::new(Pat::parse_single(input)?),
268 });
269 }
270
271 let ident = match member {
272 Member::Named(ident) => ident,
273 Member::Unnamed(_) => unreachable!(),
274 };
275
276 let pat =
277 Pat::Ident(PatIdent { attrs: Vec::new(), by_ref, mutability, ident: ident.clone() });
278
279 Ok(FieldPat {
280 attrs: Vec::new(),
281 member: Member::Named(ident),
282 colon_token: None,
283 pat: Box::new(pat),
284 })
285 }
286
287 fn pat_paren_or_tuple(input: ParseStream<'_>) -> Result<Pat> {
288 let content;
289 let paren_token = parenthesized!(content in input);
290
291 let mut elems = Punctuated::new();
292 while !content.is_empty() {
293 let value = Pat::parse_single(&content)?;
294 if content.is_empty() {
295 elems.push_value(value);
296 break;
297 }
298 elems.push_value(value);
299 let punct = content.parse()?;
300 elems.push_punct(punct);
301 }
302
303 Ok(Pat::Tuple(PatTuple { attrs: Vec::new(), paren_token, elems }))
304 }
305
306 fn pat_reference(input: ParseStream<'_>) -> Result<PatReference> {
307 Ok(PatReference {
308 attrs: Vec::new(),
309 and_token: input.parse()?,
310 mutability: input.parse()?,
311 pat: Box::new(Pat::parse_single(input)?),
312 })
313 }
314
315 fn is_unnamed(member: &Member) -> bool {
316 match member {
317 Member::Named(_) => false,
318 Member::Unnamed(_) => true,
319 }
320 }
321}
322
323mod printing {
324 use proc_macro2::TokenStream;
325 use quote::{ToTokens, TokenStreamExt};
326 use syn::Token;
327
328 use super::{
329 FieldPat, PatIdent, PatReference, PatRest, PatStruct, PatTuple, PatTupleStruct, PatType,
330 PatWild,
331 };
332
333 impl ToTokens for PatIdent {
334 fn to_tokens(&self, tokens: &mut TokenStream) {
335 tokens.append_all(&self.attrs);
336 self.by_ref.to_tokens(tokens);
337 self.mutability.to_tokens(tokens);
338 self.ident.to_tokens(tokens);
339 }
340 }
341
342 impl ToTokens for PatReference {
343 fn to_tokens(&self, tokens: &mut TokenStream) {
344 tokens.append_all(&self.attrs);
345 self.and_token.to_tokens(tokens);
346 self.mutability.to_tokens(tokens);
347 self.pat.to_tokens(tokens);
348 }
349 }
350
351 impl ToTokens for PatRest {
352 fn to_tokens(&self, tokens: &mut TokenStream) {
353 tokens.append_all(&self.attrs);
354 self.dot2_token.to_tokens(tokens);
355 }
356 }
357
358 impl ToTokens for PatStruct {
359 fn to_tokens(&self, tokens: &mut TokenStream) {
360 tokens.append_all(&self.attrs);
361 self.path.to_tokens(tokens);
362 self.brace_token.surround(tokens, |tokens| {
363 self.fields.to_tokens(tokens);
364 if !self.fields.empty_or_trailing() && self.rest.is_some() {
366 <Token![,]>::default().to_tokens(tokens);
367 }
368 self.rest.to_tokens(tokens);
369 });
370 }
371 }
372
373 impl ToTokens for PatTuple {
374 fn to_tokens(&self, tokens: &mut TokenStream) {
375 tokens.append_all(&self.attrs);
376 self.paren_token.surround(tokens, |tokens| {
377 self.elems.to_tokens(tokens);
378 });
379 }
380 }
381
382 impl ToTokens for PatTupleStruct {
383 fn to_tokens(&self, tokens: &mut TokenStream) {
384 tokens.append_all(&self.attrs);
385 self.path.to_tokens(tokens);
386 self.paren_token.surround(tokens, |tokens| {
387 self.elems.to_tokens(tokens);
388 });
389 }
390 }
391
392 impl ToTokens for PatType {
393 fn to_tokens(&self, tokens: &mut TokenStream) {
394 tokens.append_all(&self.attrs);
395 self.pat.to_tokens(tokens);
396 self.colon_token.to_tokens(tokens);
397 self.ty.to_tokens(tokens);
398 }
399 }
400
401 impl ToTokens for PatWild {
402 fn to_tokens(&self, tokens: &mut TokenStream) {
403 tokens.append_all(&self.attrs);
404 self.underscore_token.to_tokens(tokens);
405 }
406 }
407
408 impl ToTokens for FieldPat {
409 fn to_tokens(&self, tokens: &mut TokenStream) {
410 tokens.append_all(&self.attrs);
411 if let Some(colon_token) = &self.colon_token {
412 self.member.to_tokens(tokens);
413 colon_token.to_tokens(tokens);
414 }
415 self.pat.to_tokens(tokens);
416 }
417 }
418}