]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | use super::*; |
2 | use crate::punctuated::Punctuated; | |
e74abb32 | 3 | use proc_macro2::TokenStream; |
e74abb32 XL |
4 | |
5 | ast_enum_of_structs! { | |
6 | /// A pattern in a local binding, function signature, match expression, or | |
7 | /// various other places. | |
8 | /// | |
f035d41b | 9 | /// *This type is available only if Syn is built with the `"full"` feature.* |
e74abb32 XL |
10 | /// |
11 | /// # Syntax tree enum | |
12 | /// | |
13 | /// This type is a [syntax tree enum]. | |
14 | /// | |
5869c6ff XL |
15 | /// [syntax tree enum]: Expr#syntax-tree-enums |
16 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] | |
04454e1e | 17 | #[cfg_attr(not(syn_no_non_exhaustive), non_exhaustive)] |
1b1a35ee | 18 | pub enum Pat { |
e74abb32 XL |
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 | ||
04454e1e | 76 | // Not public API. |
5869c6ff | 77 | // |
04454e1e FG |
78 | // For testing exhaustiveness in downstream code, use the following idiom: |
79 | // | |
80 | // match pat { | |
81 | // Pat::Box(pat) => {...} | |
82 | // Pat::Ident(pat) => {...} | |
5869c6ff | 83 | // ... |
04454e1e | 84 | // Pat::Wild(pat) => {...} |
5869c6ff | 85 | // |
04454e1e | 86 | // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] |
5869c6ff XL |
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. | |
04454e1e | 94 | #[cfg(syn_no_non_exhaustive)] |
e74abb32 | 95 | #[doc(hidden)] |
04454e1e | 96 | __NonExhaustive, |
e74abb32 XL |
97 | } |
98 | } | |
99 | ||
100 | ast_struct! { | |
101 | /// A box pattern: `box v`. | |
102 | /// | |
f035d41b | 103 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 104 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b XL |
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.* | |
5869c6ff | 119 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 135 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 136 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 146 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 147 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 157 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 158 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 175 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 176 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 187 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 188 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 200 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 201 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 213 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 214 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 224 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 225 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 236 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 237 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 250 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 251 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 262 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 263 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 274 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 275 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 287 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 288 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | /// | |
f035d41b | 301 | /// *This type is available only if Syn is built with the `"full"` feature.* |
5869c6ff | 302 | #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
e74abb32 XL |
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 | ||
e74abb32 | 311 | #[cfg(feature = "parsing")] |
f035d41b | 312 | pub mod parsing { |
e74abb32 | 313 | use super::*; |
e74abb32 | 314 | use crate::ext::IdentExt; |
f035d41b | 315 | use crate::parse::{Parse, ParseBuffer, ParseStream, Result}; |
e74abb32 XL |
316 | use crate::path; |
317 | ||
5869c6ff | 318 | #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] |
e74abb32 XL |
319 | impl Parse for Pat { |
320 | fn parse(input: ParseStream) -> Result<Self> { | |
f035d41b | 321 | let begin = input.fork(); |
e74abb32 | 322 | let lookahead = input.lookahead1(); |
29967ef6 XL |
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![::]) | |
e74abb32 XL |
337 | || lookahead.peek(Token![<]) |
338 | || input.peek(Token![Self]) | |
339 | || input.peek(Token![super]) | |
e74abb32 XL |
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) | |
5869c6ff XL |
347 | } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const]) |
348 | { | |
e74abb32 XL |
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![...]) { | |
f035d41b | 363 | pat_range_half_open(input, begin) |
5869c6ff XL |
364 | } else if lookahead.peek(Token![const]) { |
365 | input.call(pat_const).map(Pat::Verbatim) | |
e74abb32 XL |
366 | } else { |
367 | Err(lookahead.error()) | |
368 | } | |
369 | } | |
370 | } | |
371 | ||
372 | fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { | |
f035d41b | 373 | let begin = input.fork(); |
e74abb32 XL |
374 | let (qself, path) = path::parsing::qpath(input, true)?; |
375 | ||
c295e0f8 | 376 | if qself.is_none() && input.peek(Token![!]) && !input.peek(Token![!=]) { |
e74abb32 XL |
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) { | |
2b03887a | 403 | let pat = pat_struct(begin.fork(), input, path)?; |
c295e0f8 XL |
404 | if qself.is_some() { |
405 | Ok(Pat::Verbatim(verbatim::between(begin, input))) | |
406 | } else { | |
2b03887a | 407 | Ok(pat) |
c295e0f8 | 408 | } |
e74abb32 | 409 | } else if input.peek(token::Paren) { |
c295e0f8 XL |
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 | } | |
e74abb32 | 416 | } else if input.peek(Token![..]) { |
f035d41b | 417 | pat_range(input, begin, qself, path) |
e74abb32 XL |
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 | ||
2b03887a | 468 | fn pat_struct(begin: ParseBuffer, input: ParseStream, path: Path) -> Result<Pat> { |
e74abb32 XL |
469 | let content; |
470 | let brace_token = braced!(content in input); | |
471 | ||
472 | let mut fields = Punctuated::new(); | |
2b03887a FG |
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; | |
e74abb32 | 485 | fields.push_value(value); |
f035d41b | 486 | if content.is_empty() { |
e74abb32 XL |
487 | break; |
488 | } | |
489 | let punct: Token![,] = content.parse()?; | |
490 | fields.push_punct(punct); | |
491 | } | |
492 | ||
2b03887a | 493 | Ok(Pat::Struct(PatStruct { |
e74abb32 XL |
494 | attrs: Vec::new(), |
495 | path, | |
496 | brace_token, | |
497 | fields, | |
498 | dot2_token, | |
2b03887a | 499 | })) |
e74abb32 XL |
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 { | |
2b03887a | 521 | attrs: Vec::new(), |
e74abb32 XL |
522 | member, |
523 | colon_token: input.parse()?, | |
cdc7bbd5 | 524 | pat: Box::new(multi_pat_with_leading_vert(input)?), |
e74abb32 XL |
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(), | |
e74abb32 | 544 | box_token: boxed, |
60c5eb7d | 545 | pat: Box::new(pat), |
e74abb32 XL |
546 | }); |
547 | } | |
548 | ||
549 | Ok(FieldPat { | |
2b03887a | 550 | attrs: Vec::new(), |
e74abb32 | 551 | member: Member::Named(ident), |
e74abb32 | 552 | colon_token: None, |
60c5eb7d | 553 | pat: Box::new(pat), |
e74abb32 XL |
554 | }) |
555 | } | |
556 | ||
f035d41b XL |
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 { | |
e74abb32 | 567 | attrs: Vec::new(), |
f035d41b XL |
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 | } | |
e74abb32 XL |
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() { | |
cdc7bbd5 | 603 | let value = multi_pat_with_leading_vert(&content)?; |
e74abb32 XL |
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> { | |
f035d41b XL |
629 | let begin = input.fork(); |
630 | let lo = input.call(pat_lit_expr)?.unwrap(); | |
e74abb32 | 631 | if input.peek(Token![..]) { |
f035d41b XL |
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 | } | |
5869c6ff XL |
644 | } else if let Expr::Verbatim(verbatim) = *lo { |
645 | Ok(Pat::Verbatim(verbatim)) | |
e74abb32 XL |
646 | } else { |
647 | Ok(Pat::Lit(PatLit { | |
648 | attrs: Vec::new(), | |
649 | expr: lo, | |
650 | })) | |
651 | } | |
652 | } | |
653 | ||
f035d41b XL |
654 | fn pat_lit_expr(input: ParseStream) -> Result<Option<Box<Expr>>> { |
655 | if input.is_empty() | |
656 | || input.peek(Token![|]) | |
5e7ed085 | 657 | || input.peek(Token![=]) |
f035d41b XL |
658 | || input.peek(Token![:]) && !input.peek(Token![::]) |
659 | || input.peek(Token![,]) | |
660 | || input.peek(Token![;]) | |
661 | { | |
662 | return Ok(None); | |
663 | } | |
664 | ||
e74abb32 XL |
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]) | |
e74abb32 XL |
676 | || lookahead.peek(Token![crate]) |
677 | { | |
678 | Expr::Path(input.parse()?) | |
5869c6ff XL |
679 | } else if lookahead.peek(Token![const]) { |
680 | Expr::Verbatim(input.call(expr::parsing::expr_const)?) | |
e74abb32 XL |
681 | } else { |
682 | return Err(lookahead.error()); | |
683 | }; | |
684 | ||
f035d41b | 685 | Ok(Some(Box::new(if let Some(neg) = neg { |
e74abb32 XL |
686 | Expr::Unary(ExprUnary { |
687 | attrs: Vec::new(), | |
688 | op: UnOp::Neg(neg), | |
689 | expr: Box::new(expr), | |
690 | }) | |
691 | } else { | |
692 | expr | |
f035d41b | 693 | }))) |
e74abb32 XL |
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() { | |
cdc7bbd5 | 702 | let value = multi_pat_with_leading_vert(&content)?; |
e74abb32 XL |
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 | ||
5869c6ff XL |
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 | ||
f035d41b XL |
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) | |
e74abb32 XL |
759 | } |
760 | } | |
761 | ||
762 | #[cfg(feature = "printing")] | |
763 | mod printing { | |
764 | use super::*; | |
29967ef6 | 765 | use crate::attr::FilterAttrs; |
e74abb32 XL |
766 | use proc_macro2::TokenStream; |
767 | use quote::{ToTokens, TokenStreamExt}; | |
768 | ||
5869c6ff | 769 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
770 | impl ToTokens for PatWild { |
771 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 772 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
773 | self.underscore_token.to_tokens(tokens); |
774 | } | |
775 | } | |
776 | ||
5869c6ff | 777 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
778 | impl ToTokens for PatIdent { |
779 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 780 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
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 | ||
5869c6ff | 791 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
792 | impl ToTokens for PatStruct { |
793 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 794 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
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 | ||
5869c6ff | 807 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
808 | impl ToTokens for PatTupleStruct { |
809 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 810 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
811 | self.path.to_tokens(tokens); |
812 | self.pat.to_tokens(tokens); | |
813 | } | |
814 | } | |
815 | ||
5869c6ff | 816 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
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 | ||
5869c6ff | 826 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
827 | impl ToTokens for PatPath { |
828 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 829 | tokens.append_all(self.attrs.outer()); |
04454e1e | 830 | path::printing::print_path(tokens, &self.qself, &self.path); |
e74abb32 XL |
831 | } |
832 | } | |
833 | ||
5869c6ff | 834 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
835 | impl ToTokens for PatTuple { |
836 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 837 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
838 | self.paren_token.surround(tokens, |tokens| { |
839 | self.elems.to_tokens(tokens); | |
840 | }); | |
841 | } | |
842 | } | |
843 | ||
5869c6ff | 844 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
845 | impl ToTokens for PatBox { |
846 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 847 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
848 | self.box_token.to_tokens(tokens); |
849 | self.pat.to_tokens(tokens); | |
850 | } | |
851 | } | |
852 | ||
5869c6ff | 853 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
854 | impl ToTokens for PatReference { |
855 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 856 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
857 | self.and_token.to_tokens(tokens); |
858 | self.mutability.to_tokens(tokens); | |
859 | self.pat.to_tokens(tokens); | |
860 | } | |
861 | } | |
862 | ||
5869c6ff | 863 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
864 | impl ToTokens for PatRest { |
865 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 866 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
867 | self.dot2_token.to_tokens(tokens); |
868 | } | |
869 | } | |
870 | ||
5869c6ff | 871 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
872 | impl ToTokens for PatLit { |
873 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 874 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
875 | self.expr.to_tokens(tokens); |
876 | } | |
877 | } | |
878 | ||
5869c6ff | 879 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
880 | impl ToTokens for PatRange { |
881 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 882 | tokens.append_all(self.attrs.outer()); |
e74abb32 | 883 | self.lo.to_tokens(tokens); |
04454e1e | 884 | self.limits.to_tokens(tokens); |
e74abb32 XL |
885 | self.hi.to_tokens(tokens); |
886 | } | |
887 | } | |
888 | ||
5869c6ff | 889 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
890 | impl ToTokens for PatSlice { |
891 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 892 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
893 | self.bracket_token.surround(tokens, |tokens| { |
894 | self.elems.to_tokens(tokens); | |
895 | }); | |
896 | } | |
897 | } | |
898 | ||
5869c6ff | 899 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
900 | impl ToTokens for PatMacro { |
901 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 902 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
903 | self.mac.to_tokens(tokens); |
904 | } | |
905 | } | |
906 | ||
5869c6ff | 907 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
908 | impl ToTokens for PatOr { |
909 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 910 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
911 | self.leading_vert.to_tokens(tokens); |
912 | self.cases.to_tokens(tokens); | |
913 | } | |
914 | } | |
915 | ||
5869c6ff | 916 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
e74abb32 XL |
917 | impl ToTokens for FieldPat { |
918 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
60c5eb7d | 919 | tokens.append_all(self.attrs.outer()); |
e74abb32 XL |
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 | } |