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