1 | use super::*; |
2 | use crate::punctuated::Punctuated; |
3 | use proc_macro2::TokenStream; |
4 | |
5 | ast_enum_of_structs! { |
6 | /// A pattern in a local binding, function signature, match expression, or |
7 | /// various other places. |
8 | /// |
9 | /// # Syntax tree enum |
10 | /// |
11 | /// This type is a [syntax tree enum]. |
12 | /// |
13 | /// [syntax tree enum]: Expr#syntax-tree-enums |
14 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
15 | #[non_exhaustive ] |
16 | pub enum Pat { |
17 | /// A const block: `const { ... }`. |
18 | Const(PatConst), |
19 | |
20 | /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. |
21 | Ident(PatIdent), |
22 | |
23 | /// A literal pattern: `0`. |
24 | Lit(PatLit), |
25 | |
26 | /// A macro in pattern position. |
27 | Macro(PatMacro), |
28 | |
29 | /// A pattern that matches any one of a set of cases. |
30 | Or(PatOr), |
31 | |
32 | /// A parenthesized pattern: `(A | B)`. |
33 | Paren(PatParen), |
34 | |
35 | /// A path pattern like `Color::Red`, optionally qualified with a |
36 | /// self-type. |
37 | /// |
38 | /// Unqualified path patterns can legally refer to variants, structs, |
39 | /// constants or associated constants. Qualified path patterns like |
40 | /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to |
41 | /// associated constants. |
42 | Path(PatPath), |
43 | |
44 | /// A range pattern: `1..=2`. |
45 | Range(PatRange), |
46 | |
47 | /// A reference pattern: `&mut var`. |
48 | Reference(PatReference), |
49 | |
50 | /// The dots in a tuple or slice pattern: `[0, 1, ..]`. |
51 | Rest(PatRest), |
52 | |
53 | /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. |
54 | Slice(PatSlice), |
55 | |
56 | /// A struct or struct variant pattern: `Variant { x, y, .. }`. |
57 | Struct(PatStruct), |
58 | |
59 | /// A tuple pattern: `(a, b)`. |
60 | Tuple(PatTuple), |
61 | |
62 | /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. |
63 | TupleStruct(PatTupleStruct), |
64 | |
65 | /// A type ascription pattern: `foo: f64`. |
66 | Type(PatType), |
67 | |
68 | /// Tokens in pattern position not interpreted by Syn. |
69 | Verbatim(TokenStream), |
70 | |
71 | /// A pattern that matches any value: `_`. |
72 | Wild(PatWild), |
73 | |
74 | // For testing exhaustiveness in downstream code, use the following idiom: |
75 | // |
76 | // match pat { |
77 | // Pat::Box(pat) => {...} |
78 | // Pat::Ident(pat) => {...} |
79 | // ... |
80 | // Pat::Wild(pat) => {...} |
81 | // |
82 | // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] |
83 | // _ => { /* some sane fallback */ } |
84 | // } |
85 | // |
86 | // This way we fail your tests but don't break your library when adding |
87 | // a variant. You will be notified by a test failure when a variant is |
88 | // added, so that you can add code to handle it, but your library will |
89 | // continue to compile and work for downstream users in the interim. |
90 | } |
91 | } |
92 | |
93 | ast_struct! { |
94 | /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. |
95 | /// |
96 | /// It may also be a unit struct or struct variant (e.g. `None`), or a |
97 | /// constant; these cannot be distinguished syntactically. |
98 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
99 | pub struct PatIdent { |
100 | pub attrs: Vec<Attribute>, |
101 | pub by_ref: Option<Token![ref]>, |
102 | pub mutability: Option<Token![mut]>, |
103 | pub ident: Ident, |
104 | pub subpat: Option<(Token![@], Box<Pat>)>, |
105 | } |
106 | } |
107 | |
108 | ast_struct! { |
109 | /// A pattern that matches any one of a set of cases. |
110 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
111 | pub struct PatOr { |
112 | pub attrs: Vec<Attribute>, |
113 | pub leading_vert: Option<Token![|]>, |
114 | pub cases: Punctuated<Pat, Token![|]>, |
115 | } |
116 | } |
117 | |
118 | ast_struct! { |
119 | /// A parenthesized pattern: `(A | B)`. |
120 | pub struct PatParen { |
121 | pub attrs: Vec<Attribute>, |
122 | pub paren_token: token::Paren, |
123 | pub pat: Box<Pat>, |
124 | } |
125 | } |
126 | |
127 | ast_struct! { |
128 | /// A reference pattern: `&mut var`. |
129 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
130 | pub struct PatReference { |
131 | pub attrs: Vec<Attribute>, |
132 | pub and_token: Token![&], |
133 | pub mutability: Option<Token![mut]>, |
134 | pub pat: Box<Pat>, |
135 | } |
136 | } |
137 | |
138 | ast_struct! { |
139 | /// The dots in a tuple or slice pattern: `[0, 1, ..]`. |
140 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
141 | pub struct PatRest { |
142 | pub attrs: Vec<Attribute>, |
143 | pub dot2_token: Token![..], |
144 | } |
145 | } |
146 | |
147 | ast_struct! { |
148 | /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. |
149 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
150 | pub struct PatSlice { |
151 | pub attrs: Vec<Attribute>, |
152 | pub bracket_token: token::Bracket, |
153 | pub elems: Punctuated<Pat, Token![,]>, |
154 | } |
155 | } |
156 | |
157 | ast_struct! { |
158 | /// A struct or struct variant pattern: `Variant { x, y, .. }`. |
159 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
160 | pub struct PatStruct { |
161 | pub attrs: Vec<Attribute>, |
162 | pub qself: Option<QSelf>, |
163 | pub path: Path, |
164 | pub brace_token: token::Brace, |
165 | pub fields: Punctuated<FieldPat, Token![,]>, |
166 | pub rest: Option<PatRest>, |
167 | } |
168 | } |
169 | |
170 | ast_struct! { |
171 | /// A tuple pattern: `(a, b)`. |
172 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
173 | pub struct PatTuple { |
174 | pub attrs: Vec<Attribute>, |
175 | pub paren_token: token::Paren, |
176 | pub elems: Punctuated<Pat, Token![,]>, |
177 | } |
178 | } |
179 | |
180 | ast_struct! { |
181 | /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. |
182 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
183 | pub struct PatTupleStruct { |
184 | pub attrs: Vec<Attribute>, |
185 | pub qself: Option<QSelf>, |
186 | pub path: Path, |
187 | pub paren_token: token::Paren, |
188 | pub elems: Punctuated<Pat, Token![,]>, |
189 | } |
190 | } |
191 | |
192 | ast_struct! { |
193 | /// A type ascription pattern: `foo: f64`. |
194 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
195 | pub struct PatType { |
196 | pub attrs: Vec<Attribute>, |
197 | pub pat: Box<Pat>, |
198 | pub colon_token: Token![:], |
199 | pub ty: Box<Type>, |
200 | } |
201 | } |
202 | |
203 | ast_struct! { |
204 | /// A pattern that matches any value: `_`. |
205 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
206 | pub struct PatWild { |
207 | pub attrs: Vec<Attribute>, |
208 | pub underscore_token: Token![_], |
209 | } |
210 | } |
211 | |
212 | ast_struct! { |
213 | /// A single field in a struct pattern. |
214 | /// |
215 | /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated |
216 | /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token. |
217 | #[cfg_attr (doc_cfg, doc(cfg(feature = "full" )))] |
218 | pub struct FieldPat { |
219 | pub attrs: Vec<Attribute>, |
220 | pub member: Member, |
221 | pub colon_token: Option<Token![:]>, |
222 | pub pat: Box<Pat>, |
223 | } |
224 | } |
225 | |
226 | #[cfg (feature = "parsing" )] |
227 | pub(crate) mod parsing { |
228 | use super::*; |
229 | use crate::ext::IdentExt; |
230 | use crate::parse::{ParseBuffer, ParseStream, Result}; |
231 | use crate::path; |
232 | |
233 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
234 | impl Pat { |
235 | /// Parse a pattern that does _not_ involve `|` at the top level. |
236 | /// |
237 | /// This parser matches the behavior of the `$:pat_param` macro_rules |
238 | /// matcher, and on editions prior to Rust 2021, the behavior of |
239 | /// `$:pat`. |
240 | /// |
241 | /// In Rust syntax, some examples of where this syntax would occur are |
242 | /// in the argument pattern of functions and closures. Patterns using |
243 | /// `|` are not allowed to occur in these positions. |
244 | /// |
245 | /// ```compile_fail |
246 | /// fn f(Some(_) | None: Option<T>) { |
247 | /// let _ = |Some(_) | None: Option<T>| {}; |
248 | /// // ^^^^^^^^^^^^^^^^^^^^^^^^^??? :( |
249 | /// } |
250 | /// ``` |
251 | /// |
252 | /// ```console |
253 | /// error: top-level or-patterns are not allowed in function parameters |
254 | /// --> src/main.rs:1:6 |
255 | /// | |
256 | /// 1 | fn f(Some(_) | None: Option<T>) { |
257 | /// | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)` |
258 | /// ``` |
259 | pub fn parse_single(input: ParseStream) -> Result<Self> { |
260 | let begin = input.fork(); |
261 | let lookahead = input.lookahead1(); |
262 | if lookahead.peek(Ident) |
263 | && (input.peek2(Token![::]) |
264 | || input.peek2(Token![!]) |
265 | || input.peek2(token::Brace) |
266 | || input.peek2(token::Paren) |
267 | || input.peek2(Token![..])) |
268 | || input.peek(Token![self]) && input.peek2(Token![::]) |
269 | || lookahead.peek(Token![::]) |
270 | || lookahead.peek(Token![<]) |
271 | || input.peek(Token![Self]) |
272 | || input.peek(Token![super]) |
273 | || input.peek(Token![crate]) |
274 | { |
275 | pat_path_or_macro_or_struct_or_range(input) |
276 | } else if lookahead.peek(Token![_]) { |
277 | input.call(pat_wild).map(Pat::Wild) |
278 | } else if input.peek(Token![box]) { |
279 | pat_box(begin, input) |
280 | } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const]) |
281 | { |
282 | pat_lit_or_range(input) |
283 | } else if lookahead.peek(Token![ref]) |
284 | || lookahead.peek(Token![mut]) |
285 | || input.peek(Token![self]) |
286 | || input.peek(Ident) |
287 | { |
288 | input.call(pat_ident).map(Pat::Ident) |
289 | } else if lookahead.peek(Token![&]) { |
290 | input.call(pat_reference).map(Pat::Reference) |
291 | } else if lookahead.peek(token::Paren) { |
292 | input.call(pat_paren_or_tuple) |
293 | } else if lookahead.peek(token::Bracket) { |
294 | input.call(pat_slice).map(Pat::Slice) |
295 | } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) { |
296 | pat_range_half_open(input) |
297 | } else if lookahead.peek(Token![const]) { |
298 | input.call(pat_const).map(Pat::Verbatim) |
299 | } else { |
300 | Err(lookahead.error()) |
301 | } |
302 | } |
303 | |
304 | /// Parse a pattern, possibly involving `|`, but not a leading `|`. |
305 | pub fn parse_multi(input: ParseStream) -> Result<Self> { |
306 | multi_pat_impl(input, None) |
307 | } |
308 | |
309 | /// Parse a pattern, possibly involving `|`, possibly including a |
310 | /// leading `|`. |
311 | /// |
312 | /// This parser matches the behavior of the Rust 2021 edition's `$:pat` |
313 | /// macro_rules matcher. |
314 | /// |
315 | /// In Rust syntax, an example of where this syntax would occur is in |
316 | /// the pattern of a `match` arm, where the language permits an optional |
317 | /// leading `|`, although it is not idiomatic to write one there in |
318 | /// handwritten code. |
319 | /// |
320 | /// ``` |
321 | /// # let wat = None; |
322 | /// match wat { |
323 | /// | None | Some(false) => {} |
324 | /// | Some(true) => {} |
325 | /// } |
326 | /// ``` |
327 | /// |
328 | /// The compiler accepts it only to facilitate some situations in |
329 | /// macro-generated code where a macro author might need to write: |
330 | /// |
331 | /// ``` |
332 | /// # macro_rules! doc { |
333 | /// # ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => { |
334 | /// match $value { |
335 | /// $(| $conditions1)* $(| $conditions2)* => $then |
336 | /// } |
337 | /// # }; |
338 | /// # } |
339 | /// # |
340 | /// # doc!(true, (true), (false), {}); |
341 | /// # doc!(true, (), (true, false), {}); |
342 | /// # doc!(true, (true, false), (), {}); |
343 | /// ``` |
344 | /// |
345 | /// Expressing the same thing correctly in the case that either one (but |
346 | /// not both) of `$conditions1` and `$conditions2` might be empty, |
347 | /// without leading `|`, is complex. |
348 | /// |
349 | /// Use [`Pat::parse_multi`] instead if you are not intending to support |
350 | /// macro-generated macro input. |
351 | pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> { |
352 | let leading_vert: Option<Token![|]> = input.parse()?; |
353 | multi_pat_impl(input, leading_vert) |
354 | } |
355 | } |
356 | |
357 | fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> { |
358 | let mut pat = Pat::parse_single(input)?; |
359 | if leading_vert.is_some() |
360 | || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) |
361 | { |
362 | let mut cases = Punctuated::new(); |
363 | cases.push_value(pat); |
364 | while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { |
365 | let punct = input.parse()?; |
366 | cases.push_punct(punct); |
367 | let pat = Pat::parse_single(input)?; |
368 | cases.push_value(pat); |
369 | } |
370 | pat = Pat::Or(PatOr { |
371 | attrs: Vec::new(), |
372 | leading_vert, |
373 | cases, |
374 | }); |
375 | } |
376 | Ok(pat) |
377 | } |
378 | |
379 | fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { |
380 | let (qself, path) = path::parsing::qpath(input, true)?; |
381 | |
382 | if qself.is_none() |
383 | && input.peek(Token![!]) |
384 | && !input.peek(Token![!=]) |
385 | && path.is_mod_style() |
386 | { |
387 | let bang_token: Token![!] = input.parse()?; |
388 | let (delimiter, tokens) = mac::parse_delimiter(input)?; |
389 | return Ok(Pat::Macro(ExprMacro { |
390 | attrs: Vec::new(), |
391 | mac: Macro { |
392 | path, |
393 | bang_token, |
394 | delimiter, |
395 | tokens, |
396 | }, |
397 | })); |
398 | } |
399 | |
400 | if input.peek(token::Brace) { |
401 | pat_struct(input, qself, path).map(Pat::Struct) |
402 | } else if input.peek(token::Paren) { |
403 | pat_tuple_struct(input, qself, path).map(Pat::TupleStruct) |
404 | } else if input.peek(Token![..]) { |
405 | pat_range(input, qself, path) |
406 | } else { |
407 | Ok(Pat::Path(ExprPath { |
408 | attrs: Vec::new(), |
409 | qself, |
410 | path, |
411 | })) |
412 | } |
413 | } |
414 | |
415 | fn pat_wild(input: ParseStream) -> Result<PatWild> { |
416 | Ok(PatWild { |
417 | attrs: Vec::new(), |
418 | underscore_token: input.parse()?, |
419 | }) |
420 | } |
421 | |
422 | fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> { |
423 | input.parse::<Token![box]>()?; |
424 | Pat::parse_single(input)?; |
425 | Ok(Pat::Verbatim(verbatim::between(&begin, input))) |
426 | } |
427 | |
428 | fn pat_ident(input: ParseStream) -> Result<PatIdent> { |
429 | Ok(PatIdent { |
430 | attrs: Vec::new(), |
431 | by_ref: input.parse()?, |
432 | mutability: input.parse()?, |
433 | ident: input.call(Ident::parse_any)?, |
434 | subpat: { |
435 | if input.peek(Token![@]) { |
436 | let at_token: Token![@] = input.parse()?; |
437 | let subpat = Pat::parse_single(input)?; |
438 | Some((at_token, Box::new(subpat))) |
439 | } else { |
440 | None |
441 | } |
442 | }, |
443 | }) |
444 | } |
445 | |
446 | fn pat_tuple_struct( |
447 | input: ParseStream, |
448 | qself: Option<QSelf>, |
449 | path: Path, |
450 | ) -> Result<PatTupleStruct> { |
451 | let content; |
452 | let paren_token = parenthesized!(content in input); |
453 | |
454 | let mut elems = Punctuated::new(); |
455 | while !content.is_empty() { |
456 | let value = Pat::parse_multi_with_leading_vert(&content)?; |
457 | elems.push_value(value); |
458 | if content.is_empty() { |
459 | break; |
460 | } |
461 | let punct = content.parse()?; |
462 | elems.push_punct(punct); |
463 | } |
464 | |
465 | Ok(PatTupleStruct { |
466 | attrs: Vec::new(), |
467 | qself, |
468 | path, |
469 | paren_token, |
470 | elems, |
471 | }) |
472 | } |
473 | |
474 | fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> { |
475 | let content; |
476 | let brace_token = braced!(content in input); |
477 | |
478 | let mut fields = Punctuated::new(); |
479 | let mut rest = None; |
480 | while !content.is_empty() { |
481 | let attrs = content.call(Attribute::parse_outer)?; |
482 | if content.peek(Token![..]) { |
483 | rest = Some(PatRest { |
484 | attrs, |
485 | dot2_token: content.parse()?, |
486 | }); |
487 | break; |
488 | } |
489 | let mut value = content.call(field_pat)?; |
490 | value.attrs = attrs; |
491 | fields.push_value(value); |
492 | if content.is_empty() { |
493 | break; |
494 | } |
495 | let punct: Token![,] = content.parse()?; |
496 | fields.push_punct(punct); |
497 | } |
498 | |
499 | Ok(PatStruct { |
500 | attrs: Vec::new(), |
501 | qself, |
502 | path, |
503 | brace_token, |
504 | fields, |
505 | rest, |
506 | }) |
507 | } |
508 | |
509 | impl Member { |
510 | fn is_unnamed(&self) -> bool { |
511 | match self { |
512 | Member::Named(_) => false, |
513 | Member::Unnamed(_) => true, |
514 | } |
515 | } |
516 | } |
517 | |
518 | fn field_pat(input: ParseStream) -> Result<FieldPat> { |
519 | let begin = input.fork(); |
520 | let boxed: Option<Token![box]> = input.parse()?; |
521 | let by_ref: Option<Token![ref]> = input.parse()?; |
522 | let mutability: Option<Token![mut]> = input.parse()?; |
523 | |
524 | let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() { |
525 | input.parse().map(Member::Named) |
526 | } else { |
527 | input.parse() |
528 | }?; |
529 | |
530 | if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) |
531 | || member.is_unnamed() |
532 | { |
533 | return Ok(FieldPat { |
534 | attrs: Vec::new(), |
535 | member, |
536 | colon_token: Some(input.parse()?), |
537 | pat: Box::new(Pat::parse_multi_with_leading_vert(input)?), |
538 | }); |
539 | } |
540 | |
541 | let ident = match member { |
542 | Member::Named(ident) => ident, |
543 | Member::Unnamed(_) => unreachable!(), |
544 | }; |
545 | |
546 | let pat = if boxed.is_some() { |
547 | Pat::Verbatim(verbatim::between(&begin, input)) |
548 | } else { |
549 | Pat::Ident(PatIdent { |
550 | attrs: Vec::new(), |
551 | by_ref, |
552 | mutability, |
553 | ident: ident.clone(), |
554 | subpat: None, |
555 | }) |
556 | }; |
557 | |
558 | Ok(FieldPat { |
559 | attrs: Vec::new(), |
560 | member: Member::Named(ident), |
561 | colon_token: None, |
562 | pat: Box::new(pat), |
563 | }) |
564 | } |
565 | |
566 | fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> { |
567 | let limits = RangeLimits::parse_obsolete(input)?; |
568 | let end = input.call(pat_range_bound)?; |
569 | if let (RangeLimits::Closed(_), None) = (&limits, &end) { |
570 | return Err(input.error("expected range upper bound" )); |
571 | } |
572 | Ok(Pat::Range(ExprRange { |
573 | attrs: Vec::new(), |
574 | start: Some(Box::new(Expr::Path(ExprPath { |
575 | attrs: Vec::new(), |
576 | qself, |
577 | path, |
578 | }))), |
579 | limits, |
580 | end: end.map(PatRangeBound::into_expr), |
581 | })) |
582 | } |
583 | |
584 | fn pat_range_half_open(input: ParseStream) -> Result<Pat> { |
585 | let limits: RangeLimits = input.parse()?; |
586 | let end = input.call(pat_range_bound)?; |
587 | if end.is_some() { |
588 | Ok(Pat::Range(ExprRange { |
589 | attrs: Vec::new(), |
590 | start: None, |
591 | limits, |
592 | end: end.map(PatRangeBound::into_expr), |
593 | })) |
594 | } else { |
595 | match limits { |
596 | RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest { |
597 | attrs: Vec::new(), |
598 | dot2_token, |
599 | })), |
600 | RangeLimits::Closed(_) => Err(input.error("expected range upper bound" )), |
601 | } |
602 | } |
603 | } |
604 | |
605 | fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> { |
606 | let content; |
607 | let paren_token = parenthesized!(content in input); |
608 | |
609 | let mut elems = Punctuated::new(); |
610 | while !content.is_empty() { |
611 | let value = Pat::parse_multi_with_leading_vert(&content)?; |
612 | if content.is_empty() { |
613 | if elems.is_empty() && !matches!(value, Pat::Rest(_)) { |
614 | return Ok(Pat::Paren(PatParen { |
615 | attrs: Vec::new(), |
616 | paren_token, |
617 | pat: Box::new(value), |
618 | })); |
619 | } |
620 | elems.push_value(value); |
621 | break; |
622 | } |
623 | elems.push_value(value); |
624 | let punct = content.parse()?; |
625 | elems.push_punct(punct); |
626 | } |
627 | |
628 | Ok(Pat::Tuple(PatTuple { |
629 | attrs: Vec::new(), |
630 | paren_token, |
631 | elems, |
632 | })) |
633 | } |
634 | |
635 | fn pat_reference(input: ParseStream) -> Result<PatReference> { |
636 | Ok(PatReference { |
637 | attrs: Vec::new(), |
638 | and_token: input.parse()?, |
639 | mutability: input.parse()?, |
640 | pat: Box::new(Pat::parse_single(input)?), |
641 | }) |
642 | } |
643 | |
644 | fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { |
645 | let start = input.call(pat_range_bound)?.unwrap(); |
646 | if input.peek(Token![..]) { |
647 | let limits = RangeLimits::parse_obsolete(input)?; |
648 | let end = input.call(pat_range_bound)?; |
649 | if let (RangeLimits::Closed(_), None) = (&limits, &end) { |
650 | return Err(input.error("expected range upper bound" )); |
651 | } |
652 | Ok(Pat::Range(ExprRange { |
653 | attrs: Vec::new(), |
654 | start: Some(start.into_expr()), |
655 | limits, |
656 | end: end.map(PatRangeBound::into_expr), |
657 | })) |
658 | } else { |
659 | Ok(start.into_pat()) |
660 | } |
661 | } |
662 | |
663 | // Patterns that can appear on either side of a range pattern. |
664 | enum PatRangeBound { |
665 | Const(ExprConst), |
666 | Lit(ExprLit), |
667 | Path(ExprPath), |
668 | } |
669 | |
670 | impl PatRangeBound { |
671 | fn into_expr(self) -> Box<Expr> { |
672 | Box::new(match self { |
673 | PatRangeBound::Const(pat) => Expr::Const(pat), |
674 | PatRangeBound::Lit(pat) => Expr::Lit(pat), |
675 | PatRangeBound::Path(pat) => Expr::Path(pat), |
676 | }) |
677 | } |
678 | |
679 | fn into_pat(self) -> Pat { |
680 | match self { |
681 | PatRangeBound::Const(pat) => Pat::Const(pat), |
682 | PatRangeBound::Lit(pat) => Pat::Lit(pat), |
683 | PatRangeBound::Path(pat) => Pat::Path(pat), |
684 | } |
685 | } |
686 | } |
687 | |
688 | fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> { |
689 | if input.is_empty() |
690 | || input.peek(Token![|]) |
691 | || input.peek(Token![=]) |
692 | || input.peek(Token![:]) && !input.peek(Token![::]) |
693 | || input.peek(Token![,]) |
694 | || input.peek(Token![;]) |
695 | || input.peek(Token![if]) |
696 | { |
697 | return Ok(None); |
698 | } |
699 | |
700 | let lookahead = input.lookahead1(); |
701 | let expr = if lookahead.peek(Lit) { |
702 | PatRangeBound::Lit(input.parse()?) |
703 | } else if lookahead.peek(Ident) |
704 | || lookahead.peek(Token![::]) |
705 | || lookahead.peek(Token![<]) |
706 | || lookahead.peek(Token![self]) |
707 | || lookahead.peek(Token![Self]) |
708 | || lookahead.peek(Token![super]) |
709 | || lookahead.peek(Token![crate]) |
710 | { |
711 | PatRangeBound::Path(input.parse()?) |
712 | } else if lookahead.peek(Token![const]) { |
713 | PatRangeBound::Const(input.parse()?) |
714 | } else { |
715 | return Err(lookahead.error()); |
716 | }; |
717 | |
718 | Ok(Some(expr)) |
719 | } |
720 | |
721 | fn pat_slice(input: ParseStream) -> Result<PatSlice> { |
722 | let content; |
723 | let bracket_token = bracketed!(content in input); |
724 | |
725 | let mut elems = Punctuated::new(); |
726 | while !content.is_empty() { |
727 | let value = Pat::parse_multi_with_leading_vert(&content)?; |
728 | match value { |
729 | Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => { |
730 | let (start, end) = match pat.limits { |
731 | RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]), |
732 | RangeLimits::Closed(dot_dot_eq) => { |
733 | (dot_dot_eq.spans[0], dot_dot_eq.spans[2]) |
734 | } |
735 | }; |
736 | let msg = "range pattern is not allowed unparenthesized inside slice pattern" ; |
737 | return Err(error::new2(start, end, msg)); |
738 | } |
739 | _ => {} |
740 | } |
741 | elems.push_value(value); |
742 | if content.is_empty() { |
743 | break; |
744 | } |
745 | let punct = content.parse()?; |
746 | elems.push_punct(punct); |
747 | } |
748 | |
749 | Ok(PatSlice { |
750 | attrs: Vec::new(), |
751 | bracket_token, |
752 | elems, |
753 | }) |
754 | } |
755 | |
756 | fn pat_const(input: ParseStream) -> Result<TokenStream> { |
757 | let begin = input.fork(); |
758 | input.parse::<Token![const]>()?; |
759 | |
760 | let content; |
761 | braced!(content in input); |
762 | content.call(Attribute::parse_inner)?; |
763 | content.call(Block::parse_within)?; |
764 | |
765 | Ok(verbatim::between(&begin, input)) |
766 | } |
767 | } |
768 | |
769 | #[cfg (feature = "printing" )] |
770 | mod printing { |
771 | use super::*; |
772 | use crate::attr::FilterAttrs; |
773 | use proc_macro2::TokenStream; |
774 | use quote::{ToTokens, TokenStreamExt}; |
775 | |
776 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
777 | impl ToTokens for PatIdent { |
778 | fn to_tokens(&self, tokens: &mut TokenStream) { |
779 | tokens.append_all(self.attrs.outer()); |
780 | self.by_ref.to_tokens(tokens); |
781 | self.mutability.to_tokens(tokens); |
782 | self.ident.to_tokens(tokens); |
783 | if let Some((at_token, subpat)) = &self.subpat { |
784 | at_token.to_tokens(tokens); |
785 | subpat.to_tokens(tokens); |
786 | } |
787 | } |
788 | } |
789 | |
790 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
791 | impl ToTokens for PatOr { |
792 | fn to_tokens(&self, tokens: &mut TokenStream) { |
793 | tokens.append_all(self.attrs.outer()); |
794 | self.leading_vert.to_tokens(tokens); |
795 | self.cases.to_tokens(tokens); |
796 | } |
797 | } |
798 | |
799 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
800 | impl ToTokens for PatParen { |
801 | fn to_tokens(&self, tokens: &mut TokenStream) { |
802 | tokens.append_all(self.attrs.outer()); |
803 | self.paren_token.surround(tokens, |tokens| { |
804 | self.pat.to_tokens(tokens); |
805 | }); |
806 | } |
807 | } |
808 | |
809 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
810 | impl ToTokens for PatReference { |
811 | fn to_tokens(&self, tokens: &mut TokenStream) { |
812 | tokens.append_all(self.attrs.outer()); |
813 | self.and_token.to_tokens(tokens); |
814 | self.mutability.to_tokens(tokens); |
815 | self.pat.to_tokens(tokens); |
816 | } |
817 | } |
818 | |
819 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
820 | impl ToTokens for PatRest { |
821 | fn to_tokens(&self, tokens: &mut TokenStream) { |
822 | tokens.append_all(self.attrs.outer()); |
823 | self.dot2_token.to_tokens(tokens); |
824 | } |
825 | } |
826 | |
827 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
828 | impl ToTokens for PatSlice { |
829 | fn to_tokens(&self, tokens: &mut TokenStream) { |
830 | tokens.append_all(self.attrs.outer()); |
831 | self.bracket_token.surround(tokens, |tokens| { |
832 | self.elems.to_tokens(tokens); |
833 | }); |
834 | } |
835 | } |
836 | |
837 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
838 | impl ToTokens for PatStruct { |
839 | fn to_tokens(&self, tokens: &mut TokenStream) { |
840 | tokens.append_all(self.attrs.outer()); |
841 | path::printing::print_path(tokens, &self.qself, &self.path); |
842 | self.brace_token.surround(tokens, |tokens| { |
843 | self.fields.to_tokens(tokens); |
844 | // NOTE: We need a comma before the dot2 token if it is present. |
845 | if !self.fields.empty_or_trailing() && self.rest.is_some() { |
846 | <Token![,]>::default().to_tokens(tokens); |
847 | } |
848 | self.rest.to_tokens(tokens); |
849 | }); |
850 | } |
851 | } |
852 | |
853 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
854 | impl ToTokens for PatTuple { |
855 | fn to_tokens(&self, tokens: &mut TokenStream) { |
856 | tokens.append_all(self.attrs.outer()); |
857 | self.paren_token.surround(tokens, |tokens| { |
858 | self.elems.to_tokens(tokens); |
859 | }); |
860 | } |
861 | } |
862 | |
863 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
864 | impl ToTokens for PatTupleStruct { |
865 | fn to_tokens(&self, tokens: &mut TokenStream) { |
866 | tokens.append_all(self.attrs.outer()); |
867 | path::printing::print_path(tokens, &self.qself, &self.path); |
868 | self.paren_token.surround(tokens, |tokens| { |
869 | self.elems.to_tokens(tokens); |
870 | }); |
871 | } |
872 | } |
873 | |
874 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
875 | impl ToTokens for PatType { |
876 | fn to_tokens(&self, tokens: &mut TokenStream) { |
877 | tokens.append_all(self.attrs.outer()); |
878 | self.pat.to_tokens(tokens); |
879 | self.colon_token.to_tokens(tokens); |
880 | self.ty.to_tokens(tokens); |
881 | } |
882 | } |
883 | |
884 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
885 | impl ToTokens for PatWild { |
886 | fn to_tokens(&self, tokens: &mut TokenStream) { |
887 | tokens.append_all(self.attrs.outer()); |
888 | self.underscore_token.to_tokens(tokens); |
889 | } |
890 | } |
891 | |
892 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
893 | impl ToTokens for FieldPat { |
894 | fn to_tokens(&self, tokens: &mut TokenStream) { |
895 | tokens.append_all(self.attrs.outer()); |
896 | if let Some(colon_token) = &self.colon_token { |
897 | self.member.to_tokens(tokens); |
898 | colon_token.to_tokens(tokens); |
899 | } |
900 | self.pat.to_tokens(tokens); |
901 | } |
902 | } |
903 | } |
904 | |