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