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