| use super::*; |
| use crate::punctuated::Punctuated; |
| use proc_macro2::TokenStream; |
| |
| ast_enum_of_structs! { |
| /// A pattern in a local binding, function signature, match expression, or |
| /// various other places. |
| /// |
| /// # Syntax tree enum |
| /// |
| /// This type is a [syntax tree enum]. |
| /// |
| /// [syntax tree enum]: Expr#syntax-tree-enums |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| #[non_exhaustive] |
| pub enum Pat { |
| /// A const block: `const { ... }`. |
| Const(PatConst), |
| |
| /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. |
| Ident(PatIdent), |
| |
| /// A literal pattern: `0`. |
| Lit(PatLit), |
| |
| /// A macro in pattern position. |
| Macro(PatMacro), |
| |
| /// A pattern that matches any one of a set of cases. |
| Or(PatOr), |
| |
| /// A parenthesized pattern: `(A | B)`. |
| Paren(PatParen), |
| |
| /// A path pattern like `Color::Red`, optionally qualified with a |
| /// self-type. |
| /// |
| /// Unqualified path patterns can legally refer to variants, structs, |
| /// constants or associated constants. Qualified path patterns like |
| /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to |
| /// associated constants. |
| Path(PatPath), |
| |
| /// A range pattern: `1..=2`. |
| Range(PatRange), |
| |
| /// A reference pattern: `&mut var`. |
| Reference(PatReference), |
| |
| /// The dots in a tuple or slice pattern: `[0, 1, ..]`. |
| Rest(PatRest), |
| |
| /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. |
| Slice(PatSlice), |
| |
| /// A struct or struct variant pattern: `Variant { x, y, .. }`. |
| Struct(PatStruct), |
| |
| /// A tuple pattern: `(a, b)`. |
| Tuple(PatTuple), |
| |
| /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. |
| TupleStruct(PatTupleStruct), |
| |
| /// A type ascription pattern: `foo: f64`. |
| Type(PatType), |
| |
| /// Tokens in pattern position not interpreted by Syn. |
| Verbatim(TokenStream), |
| |
| /// A pattern that matches any value: `_`. |
| Wild(PatWild), |
| |
| // For testing exhaustiveness in downstream code, use the following idiom: |
| // |
| // match pat { |
| // Pat::Box(pat) => {...} |
| // Pat::Ident(pat) => {...} |
| // ... |
| // Pat::Wild(pat) => {...} |
| // |
| // #[cfg_attr(test, deny(non_exhaustive_omitted_patterns))] |
| // _ => { /* some sane fallback */ } |
| // } |
| // |
| // This way we fail your tests but don't break your library when adding |
| // a variant. You will be notified by a test failure when a variant is |
| // added, so that you can add code to handle it, but your library will |
| // continue to compile and work for downstream users in the interim. |
| } |
| } |
| |
| ast_struct! { |
| /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. |
| /// |
| /// It may also be a unit struct or struct variant (e.g. `None`), or a |
| /// constant; these cannot be distinguished syntactically. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatIdent { |
| pub attrs: Vec<Attribute>, |
| pub by_ref: Option<Token![ref]>, |
| pub mutability: Option<Token![mut]>, |
| pub ident: Ident, |
| pub subpat: Option<(Token![@], Box<Pat>)>, |
| } |
| } |
| |
| ast_struct! { |
| /// A pattern that matches any one of a set of cases. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatOr { |
| pub attrs: Vec<Attribute>, |
| pub leading_vert: Option<Token![|]>, |
| pub cases: Punctuated<Pat, Token![|]>, |
| } |
| } |
| |
| ast_struct! { |
| /// A parenthesized pattern: `(A | B)`. |
| pub struct PatParen { |
| pub attrs: Vec<Attribute>, |
| pub paren_token: token::Paren, |
| pub pat: Box<Pat>, |
| } |
| } |
| |
| ast_struct! { |
| /// A reference pattern: `&mut var`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatReference { |
| pub attrs: Vec<Attribute>, |
| pub and_token: Token![&], |
| pub mutability: Option<Token![mut]>, |
| pub pat: Box<Pat>, |
| } |
| } |
| |
| ast_struct! { |
| /// The dots in a tuple or slice pattern: `[0, 1, ..]`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatRest { |
| pub attrs: Vec<Attribute>, |
| pub dot2_token: Token![..], |
| } |
| } |
| |
| ast_struct! { |
| /// A dynamically sized slice pattern: `[a, b, ref i @ .., y, z]`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatSlice { |
| pub attrs: Vec<Attribute>, |
| pub bracket_token: token::Bracket, |
| pub elems: Punctuated<Pat, Token![,]>, |
| } |
| } |
| |
| ast_struct! { |
| /// A struct or struct variant pattern: `Variant { x, y, .. }`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatStruct { |
| pub attrs: Vec<Attribute>, |
| pub qself: Option<QSelf>, |
| pub path: Path, |
| pub brace_token: token::Brace, |
| pub fields: Punctuated<FieldPat, Token![,]>, |
| pub rest: Option<PatRest>, |
| } |
| } |
| |
| ast_struct! { |
| /// A tuple pattern: `(a, b)`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatTuple { |
| pub attrs: Vec<Attribute>, |
| pub paren_token: token::Paren, |
| pub elems: Punctuated<Pat, Token![,]>, |
| } |
| } |
| |
| ast_struct! { |
| /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatTupleStruct { |
| pub attrs: Vec<Attribute>, |
| pub qself: Option<QSelf>, |
| pub path: Path, |
| pub paren_token: token::Paren, |
| pub elems: Punctuated<Pat, Token![,]>, |
| } |
| } |
| |
| ast_struct! { |
| /// A type ascription pattern: `foo: f64`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatType { |
| pub attrs: Vec<Attribute>, |
| pub pat: Box<Pat>, |
| pub colon_token: Token![:], |
| pub ty: Box<Type>, |
| } |
| } |
| |
| ast_struct! { |
| /// A pattern that matches any value: `_`. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatWild { |
| pub attrs: Vec<Attribute>, |
| pub underscore_token: Token![_], |
| } |
| } |
| |
| ast_struct! { |
| /// A single field in a struct pattern. |
| /// |
| /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated |
| /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token. |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct FieldPat { |
| pub attrs: Vec<Attribute>, |
| pub member: Member, |
| pub colon_token: Option<Token![:]>, |
| pub pat: Box<Pat>, |
| } |
| } |
| |
| #[cfg(feature = "parsing")] |
| pub(crate) mod parsing { |
| use super::*; |
| use crate::ext::IdentExt; |
| use crate::parse::{ParseBuffer, ParseStream, Result}; |
| use crate::path; |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] |
| impl Pat { |
| /// Parse a pattern that does _not_ involve `|` at the top level. |
| /// |
| /// This parser matches the behavior of the `$:pat_param` macro_rules |
| /// matcher, and on editions prior to Rust 2021, the behavior of |
| /// `$:pat`. |
| /// |
| /// In Rust syntax, some examples of where this syntax would occur are |
| /// in the argument pattern of functions and closures. Patterns using |
| /// `|` are not allowed to occur in these positions. |
| /// |
| /// ```compile_fail |
| /// fn f(Some(_) | None: Option<T>) { |
| /// let _ = |Some(_) | None: Option<T>| {}; |
| /// // ^^^^^^^^^^^^^^^^^^^^^^^^^??? :( |
| /// } |
| /// ``` |
| /// |
| /// ```console |
| /// error: top-level or-patterns are not allowed in function parameters |
| /// --> src/main.rs:1:6 |
| /// | |
| /// 1 | fn f(Some(_) | None: Option<T>) { |
| /// | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Some(_) | None)` |
| /// ``` |
| pub fn parse_single(input: ParseStream) -> Result<Self> { |
| let begin = input.fork(); |
| let lookahead = input.lookahead1(); |
| if lookahead.peek(Ident) |
| && (input.peek2(Token![::]) |
| || input.peek2(Token![!]) |
| || input.peek2(token::Brace) |
| || input.peek2(token::Paren) |
| || input.peek2(Token![..])) |
| || input.peek(Token![self]) && input.peek2(Token![::]) |
| || lookahead.peek(Token![::]) |
| || lookahead.peek(Token![<]) |
| || input.peek(Token![Self]) |
| || input.peek(Token![super]) |
| || input.peek(Token![crate]) |
| { |
| pat_path_or_macro_or_struct_or_range(input) |
| } else if lookahead.peek(Token![_]) { |
| input.call(pat_wild).map(Pat::Wild) |
| } else if input.peek(Token![box]) { |
| pat_box(begin, input) |
| } else if input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const]) |
| { |
| pat_lit_or_range(input) |
| } else if lookahead.peek(Token![ref]) |
| || lookahead.peek(Token![mut]) |
| || input.peek(Token![self]) |
| || input.peek(Ident) |
| { |
| input.call(pat_ident).map(Pat::Ident) |
| } else if lookahead.peek(Token![&]) { |
| input.call(pat_reference).map(Pat::Reference) |
| } else if lookahead.peek(token::Paren) { |
| input.call(pat_paren_or_tuple) |
| } else if lookahead.peek(token::Bracket) { |
| input.call(pat_slice).map(Pat::Slice) |
| } else if lookahead.peek(Token![..]) && !input.peek(Token![...]) { |
| pat_range_half_open(input) |
| } else if lookahead.peek(Token![const]) { |
| input.call(pat_const).map(Pat::Verbatim) |
| } else { |
| Err(lookahead.error()) |
| } |
| } |
| |
| /// Parse a pattern, possibly involving `|`, but not a leading `|`. |
| pub fn parse_multi(input: ParseStream) -> Result<Self> { |
| multi_pat_impl(input, None) |
| } |
| |
| /// Parse a pattern, possibly involving `|`, possibly including a |
| /// leading `|`. |
| /// |
| /// This parser matches the behavior of the Rust 2021 edition's `$:pat` |
| /// macro_rules matcher. |
| /// |
| /// In Rust syntax, an example of where this syntax would occur is in |
| /// the pattern of a `match` arm, where the language permits an optional |
| /// leading `|`, although it is not idiomatic to write one there in |
| /// handwritten code. |
| /// |
| /// ``` |
| /// # let wat = None; |
| /// match wat { |
| /// | None | Some(false) => {} |
| /// | Some(true) => {} |
| /// } |
| /// ``` |
| /// |
| /// The compiler accepts it only to facilitate some situations in |
| /// macro-generated code where a macro author might need to write: |
| /// |
| /// ``` |
| /// # macro_rules! doc { |
| /// # ($value:expr, ($($conditions1:pat),*), ($($conditions2:pat),*), $then:expr) => { |
| /// match $value { |
| /// $(| $conditions1)* $(| $conditions2)* => $then |
| /// } |
| /// # }; |
| /// # } |
| /// # |
| /// # doc!(true, (true), (false), {}); |
| /// # doc!(true, (), (true, false), {}); |
| /// # doc!(true, (true, false), (), {}); |
| /// ``` |
| /// |
| /// Expressing the same thing correctly in the case that either one (but |
| /// not both) of `$conditions1` and `$conditions2` might be empty, |
| /// without leading `|`, is complex. |
| /// |
| /// Use [`Pat::parse_multi`] instead if you are not intending to support |
| /// macro-generated macro input. |
| pub fn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> { |
| let leading_vert: Option<Token![|]> = input.parse()?; |
| multi_pat_impl(input, leading_vert) |
| } |
| } |
| |
| fn multi_pat_impl(input: ParseStream, leading_vert: Option<Token![|]>) -> Result<Pat> { |
| let mut pat = Pat::parse_single(input)?; |
| if leading_vert.is_some() |
| || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) |
| { |
| let mut cases = Punctuated::new(); |
| cases.push_value(pat); |
| while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { |
| let punct = input.parse()?; |
| cases.push_punct(punct); |
| let pat = Pat::parse_single(input)?; |
| cases.push_value(pat); |
| } |
| pat = Pat::Or(PatOr { |
| attrs: Vec::new(), |
| leading_vert, |
| cases, |
| }); |
| } |
| Ok(pat) |
| } |
| |
| fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { |
| let (qself, path) = path::parsing::qpath(input, true)?; |
| |
| if qself.is_none() |
| && input.peek(Token![!]) |
| && !input.peek(Token![!=]) |
| && path.is_mod_style() |
| { |
| let bang_token: Token![!] = input.parse()?; |
| let (delimiter, tokens) = mac::parse_delimiter(input)?; |
| return Ok(Pat::Macro(ExprMacro { |
| attrs: Vec::new(), |
| mac: Macro { |
| path, |
| bang_token, |
| delimiter, |
| tokens, |
| }, |
| })); |
| } |
| |
| if input.peek(token::Brace) { |
| pat_struct(input, qself, path).map(Pat::Struct) |
| } else if input.peek(token::Paren) { |
| pat_tuple_struct(input, qself, path).map(Pat::TupleStruct) |
| } else if input.peek(Token![..]) { |
| pat_range(input, qself, path) |
| } else { |
| Ok(Pat::Path(ExprPath { |
| attrs: Vec::new(), |
| qself, |
| path, |
| })) |
| } |
| } |
| |
| fn pat_wild(input: ParseStream) -> Result<PatWild> { |
| Ok(PatWild { |
| attrs: Vec::new(), |
| underscore_token: input.parse()?, |
| }) |
| } |
| |
| fn pat_box(begin: ParseBuffer, input: ParseStream) -> Result<Pat> { |
| input.parse::<Token![box]>()?; |
| Pat::parse_single(input)?; |
| Ok(Pat::Verbatim(verbatim::between(&begin, input))) |
| } |
| |
| fn pat_ident(input: ParseStream) -> Result<PatIdent> { |
| Ok(PatIdent { |
| attrs: Vec::new(), |
| by_ref: input.parse()?, |
| mutability: input.parse()?, |
| ident: input.call(Ident::parse_any)?, |
| subpat: { |
| if input.peek(Token![@]) { |
| let at_token: Token![@] = input.parse()?; |
| let subpat = Pat::parse_single(input)?; |
| Some((at_token, Box::new(subpat))) |
| } else { |
| None |
| } |
| }, |
| }) |
| } |
| |
| fn pat_tuple_struct( |
| input: ParseStream, |
| qself: Option<QSelf>, |
| path: Path, |
| ) -> Result<PatTupleStruct> { |
| let content; |
| let paren_token = parenthesized!(content in input); |
| |
| let mut elems = Punctuated::new(); |
| while !content.is_empty() { |
| let value = Pat::parse_multi_with_leading_vert(&content)?; |
| elems.push_value(value); |
| if content.is_empty() { |
| break; |
| } |
| let punct = content.parse()?; |
| elems.push_punct(punct); |
| } |
| |
| Ok(PatTupleStruct { |
| attrs: Vec::new(), |
| qself, |
| path, |
| paren_token, |
| elems, |
| }) |
| } |
| |
| fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> { |
| let content; |
| let brace_token = braced!(content in input); |
| |
| let mut fields = Punctuated::new(); |
| let mut rest = None; |
| while !content.is_empty() { |
| let attrs = content.call(Attribute::parse_outer)?; |
| if content.peek(Token![..]) { |
| rest = Some(PatRest { |
| attrs, |
| dot2_token: content.parse()?, |
| }); |
| break; |
| } |
| let mut value = content.call(field_pat)?; |
| value.attrs = attrs; |
| fields.push_value(value); |
| if content.is_empty() { |
| break; |
| } |
| let punct: Token![,] = content.parse()?; |
| fields.push_punct(punct); |
| } |
| |
| Ok(PatStruct { |
| attrs: Vec::new(), |
| qself, |
| path, |
| brace_token, |
| fields, |
| rest, |
| }) |
| } |
| |
| impl Member { |
| fn is_unnamed(&self) -> bool { |
| match self { |
| Member::Named(_) => false, |
| Member::Unnamed(_) => true, |
| } |
| } |
| } |
| |
| fn field_pat(input: ParseStream) -> Result<FieldPat> { |
| let begin = input.fork(); |
| let boxed: Option<Token![box]> = input.parse()?; |
| let by_ref: Option<Token![ref]> = input.parse()?; |
| let mutability: Option<Token![mut]> = input.parse()?; |
| |
| let member = if boxed.is_some() || by_ref.is_some() || mutability.is_some() { |
| input.parse().map(Member::Named) |
| } else { |
| input.parse() |
| }?; |
| |
| if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) |
| || member.is_unnamed() |
| { |
| return Ok(FieldPat { |
| attrs: Vec::new(), |
| member, |
| colon_token: Some(input.parse()?), |
| pat: Box::new(Pat::parse_multi_with_leading_vert(input)?), |
| }); |
| } |
| |
| let ident = match member { |
| Member::Named(ident) => ident, |
| Member::Unnamed(_) => unreachable!(), |
| }; |
| |
| let pat = if boxed.is_some() { |
| Pat::Verbatim(verbatim::between(&begin, input)) |
| } else { |
| Pat::Ident(PatIdent { |
| attrs: Vec::new(), |
| by_ref, |
| mutability, |
| ident: ident.clone(), |
| subpat: None, |
| }) |
| }; |
| |
| Ok(FieldPat { |
| attrs: Vec::new(), |
| member: Member::Named(ident), |
| colon_token: None, |
| pat: Box::new(pat), |
| }) |
| } |
| |
| fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<Pat> { |
| let limits = RangeLimits::parse_obsolete(input)?; |
| let end = input.call(pat_range_bound)?; |
| if let (RangeLimits::Closed(_), None) = (&limits, &end) { |
| return Err(input.error("expected range upper bound")); |
| } |
| Ok(Pat::Range(ExprRange { |
| attrs: Vec::new(), |
| start: Some(Box::new(Expr::Path(ExprPath { |
| attrs: Vec::new(), |
| qself, |
| path, |
| }))), |
| limits, |
| end: end.map(PatRangeBound::into_expr), |
| })) |
| } |
| |
| fn pat_range_half_open(input: ParseStream) -> Result<Pat> { |
| let limits: RangeLimits = input.parse()?; |
| let end = input.call(pat_range_bound)?; |
| if end.is_some() { |
| Ok(Pat::Range(ExprRange { |
| attrs: Vec::new(), |
| start: None, |
| limits, |
| end: end.map(PatRangeBound::into_expr), |
| })) |
| } else { |
| match limits { |
| RangeLimits::HalfOpen(dot2_token) => Ok(Pat::Rest(PatRest { |
| attrs: Vec::new(), |
| dot2_token, |
| })), |
| RangeLimits::Closed(_) => Err(input.error("expected range upper bound")), |
| } |
| } |
| } |
| |
| fn pat_paren_or_tuple(input: ParseStream) -> Result<Pat> { |
| let content; |
| let paren_token = parenthesized!(content in input); |
| |
| let mut elems = Punctuated::new(); |
| while !content.is_empty() { |
| let value = Pat::parse_multi_with_leading_vert(&content)?; |
| if content.is_empty() { |
| if elems.is_empty() && !matches!(value, Pat::Rest(_)) { |
| return Ok(Pat::Paren(PatParen { |
| attrs: Vec::new(), |
| paren_token, |
| pat: Box::new(value), |
| })); |
| } |
| elems.push_value(value); |
| break; |
| } |
| elems.push_value(value); |
| let punct = content.parse()?; |
| elems.push_punct(punct); |
| } |
| |
| Ok(Pat::Tuple(PatTuple { |
| attrs: Vec::new(), |
| paren_token, |
| elems, |
| })) |
| } |
| |
| fn pat_reference(input: ParseStream) -> Result<PatReference> { |
| Ok(PatReference { |
| attrs: Vec::new(), |
| and_token: input.parse()?, |
| mutability: input.parse()?, |
| pat: Box::new(Pat::parse_single(input)?), |
| }) |
| } |
| |
| fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { |
| let start = input.call(pat_range_bound)?.unwrap(); |
| if input.peek(Token![..]) { |
| let limits = RangeLimits::parse_obsolete(input)?; |
| let end = input.call(pat_range_bound)?; |
| if let (RangeLimits::Closed(_), None) = (&limits, &end) { |
| return Err(input.error("expected range upper bound")); |
| } |
| Ok(Pat::Range(ExprRange { |
| attrs: Vec::new(), |
| start: Some(start.into_expr()), |
| limits, |
| end: end.map(PatRangeBound::into_expr), |
| })) |
| } else { |
| Ok(start.into_pat()) |
| } |
| } |
| |
| // Patterns that can appear on either side of a range pattern. |
| enum PatRangeBound { |
| Const(ExprConst), |
| Lit(ExprLit), |
| Path(ExprPath), |
| } |
| |
| impl PatRangeBound { |
| fn into_expr(self) -> Box<Expr> { |
| Box::new(match self { |
| PatRangeBound::Const(pat) => Expr::Const(pat), |
| PatRangeBound::Lit(pat) => Expr::Lit(pat), |
| PatRangeBound::Path(pat) => Expr::Path(pat), |
| }) |
| } |
| |
| fn into_pat(self) -> Pat { |
| match self { |
| PatRangeBound::Const(pat) => Pat::Const(pat), |
| PatRangeBound::Lit(pat) => Pat::Lit(pat), |
| PatRangeBound::Path(pat) => Pat::Path(pat), |
| } |
| } |
| } |
| |
| fn pat_range_bound(input: ParseStream) -> Result<Option<PatRangeBound>> { |
| if input.is_empty() |
| || input.peek(Token![|]) |
| || input.peek(Token![=]) |
| || input.peek(Token![:]) && !input.peek(Token![::]) |
| || input.peek(Token![,]) |
| || input.peek(Token![;]) |
| || input.peek(Token![if]) |
| { |
| return Ok(None); |
| } |
| |
| let lookahead = input.lookahead1(); |
| let expr = if lookahead.peek(Lit) { |
| PatRangeBound::Lit(input.parse()?) |
| } else if lookahead.peek(Ident) |
| || lookahead.peek(Token![::]) |
| || lookahead.peek(Token![<]) |
| || lookahead.peek(Token![self]) |
| || lookahead.peek(Token![Self]) |
| || lookahead.peek(Token![super]) |
| || lookahead.peek(Token![crate]) |
| { |
| PatRangeBound::Path(input.parse()?) |
| } else if lookahead.peek(Token![const]) { |
| PatRangeBound::Const(input.parse()?) |
| } else { |
| return Err(lookahead.error()); |
| }; |
| |
| Ok(Some(expr)) |
| } |
| |
| fn pat_slice(input: ParseStream) -> Result<PatSlice> { |
| let content; |
| let bracket_token = bracketed!(content in input); |
| |
| let mut elems = Punctuated::new(); |
| while !content.is_empty() { |
| let value = Pat::parse_multi_with_leading_vert(&content)?; |
| match value { |
| Pat::Range(pat) if pat.start.is_none() || pat.end.is_none() => { |
| let (start, end) = match pat.limits { |
| RangeLimits::HalfOpen(dot_dot) => (dot_dot.spans[0], dot_dot.spans[1]), |
| RangeLimits::Closed(dot_dot_eq) => { |
| (dot_dot_eq.spans[0], dot_dot_eq.spans[2]) |
| } |
| }; |
| let msg = "range pattern is not allowed unparenthesized inside slice pattern"; |
| return Err(error::new2(start, end, msg)); |
| } |
| _ => {} |
| } |
| elems.push_value(value); |
| if content.is_empty() { |
| break; |
| } |
| let punct = content.parse()?; |
| elems.push_punct(punct); |
| } |
| |
| Ok(PatSlice { |
| attrs: Vec::new(), |
| bracket_token, |
| elems, |
| }) |
| } |
| |
| fn pat_const(input: ParseStream) -> Result<TokenStream> { |
| let begin = input.fork(); |
| input.parse::<Token![const]>()?; |
| |
| let content; |
| braced!(content in input); |
| content.call(Attribute::parse_inner)?; |
| content.call(Block::parse_within)?; |
| |
| Ok(verbatim::between(&begin, input)) |
| } |
| } |
| |
| #[cfg(feature = "printing")] |
| mod printing { |
| use super::*; |
| use crate::attr::FilterAttrs; |
| use proc_macro2::TokenStream; |
| use quote::{ToTokens, TokenStreamExt}; |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatIdent { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.by_ref.to_tokens(tokens); |
| self.mutability.to_tokens(tokens); |
| self.ident.to_tokens(tokens); |
| if let Some((at_token, subpat)) = &self.subpat { |
| at_token.to_tokens(tokens); |
| subpat.to_tokens(tokens); |
| } |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatOr { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.leading_vert.to_tokens(tokens); |
| self.cases.to_tokens(tokens); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatParen { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.paren_token.surround(tokens, |tokens| { |
| self.pat.to_tokens(tokens); |
| }); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatReference { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.and_token.to_tokens(tokens); |
| self.mutability.to_tokens(tokens); |
| self.pat.to_tokens(tokens); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatRest { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.dot2_token.to_tokens(tokens); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatSlice { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.bracket_token.surround(tokens, |tokens| { |
| self.elems.to_tokens(tokens); |
| }); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatStruct { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| path::printing::print_path(tokens, &self.qself, &self.path); |
| self.brace_token.surround(tokens, |tokens| { |
| self.fields.to_tokens(tokens); |
| // NOTE: We need a comma before the dot2 token if it is present. |
| if !self.fields.empty_or_trailing() && self.rest.is_some() { |
| <Token![,]>::default().to_tokens(tokens); |
| } |
| self.rest.to_tokens(tokens); |
| }); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatTuple { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.paren_token.surround(tokens, |tokens| { |
| self.elems.to_tokens(tokens); |
| }); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatTupleStruct { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| path::printing::print_path(tokens, &self.qself, &self.path); |
| self.paren_token.surround(tokens, |tokens| { |
| self.elems.to_tokens(tokens); |
| }); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatType { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.pat.to_tokens(tokens); |
| self.colon_token.to_tokens(tokens); |
| self.ty.to_tokens(tokens); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatWild { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.underscore_token.to_tokens(tokens); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for FieldPat { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| if let Some(colon_token) = &self.colon_token { |
| self.member.to_tokens(tokens); |
| colon_token.to_tokens(tokens); |
| } |
| self.pat.to_tokens(tokens); |
| } |
| } |
| } |