| 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. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| /// |
| /// # 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")))] |
| pub enum Pat { |
| /// A box pattern: `box v`. |
| Box(PatBox), |
| |
| /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. |
| Ident(PatIdent), |
| |
| /// A literal pattern: `0`. |
| /// |
| /// This holds an `Expr` rather than a `Lit` because negative numbers |
| /// are represented as an `Expr::Unary`. |
| Lit(PatLit), |
| |
| /// A macro in pattern position. |
| Macro(PatMacro), |
| |
| /// A pattern that matches any one of a set of cases. |
| Or(PatOr), |
| |
| /// 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), |
| |
| // The following is the only supported idiom for exhaustive matching of |
| // this enum. |
| // |
| // match expr { |
| // Pat::Box(e) => {...} |
| // Pat::Ident(e) => {...} |
| // ... |
| // Pat::Wild(e) => {...} |
| // |
| // #[cfg(test)] |
| // Pat::__TestExhaustive(_) => unimplemented!(), |
| // #[cfg(not(test))] |
| // _ => { /* 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. |
| // |
| // Once `deny(reachable)` is available in rustc, Pat will be |
| // reimplemented as a non_exhaustive enum. |
| // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 |
| #[doc(hidden)] |
| __TestExhaustive(crate::private), |
| } |
| } |
| |
| ast_struct! { |
| /// A box pattern: `box v`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatBox { |
| pub attrs: Vec<Attribute>, |
| pub box_token: Token![box], |
| pub pat: Box<Pat>, |
| } |
| } |
| |
| 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. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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 literal pattern: `0`. |
| /// |
| /// This holds an `Expr` rather than a `Lit` because negative numbers |
| /// are represented as an `Expr::Unary`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatLit { |
| pub attrs: Vec<Attribute>, |
| pub expr: Box<Expr>, |
| } |
| } |
| |
| ast_struct! { |
| /// A macro in pattern position. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatMacro { |
| pub attrs: Vec<Attribute>, |
| pub mac: Macro, |
| } |
| } |
| |
| ast_struct! { |
| /// A pattern that matches any one of a set of cases. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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 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. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatPath { |
| pub attrs: Vec<Attribute>, |
| pub qself: Option<QSelf>, |
| pub path: Path, |
| } |
| } |
| |
| ast_struct! { |
| /// A range pattern: `1..=2`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatRange { |
| pub attrs: Vec<Attribute>, |
| pub lo: Box<Expr>, |
| pub limits: RangeLimits, |
| pub hi: Box<Expr>, |
| } |
| } |
| |
| ast_struct! { |
| /// A reference pattern: `&mut var`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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, ..]` |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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]`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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, .. }`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatStruct { |
| pub attrs: Vec<Attribute>, |
| pub path: Path, |
| pub brace_token: token::Brace, |
| pub fields: Punctuated<FieldPat, Token![,]>, |
| pub dot2_token: Option<Token![..]>, |
| } |
| } |
| |
| ast_struct! { |
| /// A tuple pattern: `(a, b)`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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)`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] |
| pub struct PatTupleStruct { |
| pub attrs: Vec<Attribute>, |
| pub path: Path, |
| pub pat: PatTuple, |
| } |
| } |
| |
| ast_struct! { |
| /// A type ascription pattern: `foo: f64`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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: `_`. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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. |
| /// |
| /// *This type is available only if Syn is built with the `"full"` feature.* |
| #[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 mod parsing { |
| use super::*; |
| use crate::ext::IdentExt; |
| use crate::parse::{Parse, ParseBuffer, ParseStream, Result}; |
| use crate::path; |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] |
| impl Parse for Pat { |
| fn parse(input: ParseStream) -> Result<Self> { |
| let begin = input.fork(); |
| let lookahead = input.lookahead1(); |
| if { |
| let ahead = input.fork(); |
| ahead.parse::<Option<Ident>>()?.is_some() |
| && (ahead.peek(Token![::]) |
| || ahead.peek(Token![!]) |
| || ahead.peek(token::Brace) |
| || ahead.peek(token::Paren) |
| || ahead.peek(Token![..]) |
| && ahead.parse::<RangeLimits>().is_ok() |
| && !(ahead.is_empty() || ahead.peek(Token![,]))) |
| } || { |
| let ahead = input.fork(); |
| ahead.parse::<Option<Token![self]>>()?.is_some() && ahead.peek(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]) { |
| input.call(pat_box).map(Pat::Box) |
| } 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_tuple).map(Pat::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, begin) |
| } else if lookahead.peek(Token![const]) { |
| input.call(pat_const).map(Pat::Verbatim) |
| } else { |
| Err(lookahead.error()) |
| } |
| } |
| } |
| |
| fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { |
| let begin = input.fork(); |
| let (qself, path) = path::parsing::qpath(input, true)?; |
| |
| if qself.is_none() && input.peek(Token![!]) && !input.peek(Token![!=]) { |
| let mut contains_arguments = false; |
| for segment in &path.segments { |
| match segment.arguments { |
| PathArguments::None => {} |
| PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { |
| contains_arguments = true; |
| } |
| } |
| } |
| |
| if !contains_arguments { |
| let bang_token: Token![!] = input.parse()?; |
| let (delimiter, tokens) = mac::parse_delimiter(input)?; |
| return Ok(Pat::Macro(PatMacro { |
| attrs: Vec::new(), |
| mac: Macro { |
| path, |
| bang_token, |
| delimiter, |
| tokens, |
| }, |
| })); |
| } |
| } |
| |
| if input.peek(token::Brace) { |
| let pat = pat_struct(input, path)?; |
| if qself.is_some() { |
| Ok(Pat::Verbatim(verbatim::between(begin, input))) |
| } else { |
| Ok(Pat::Struct(pat)) |
| } |
| } else if input.peek(token::Paren) { |
| let pat = pat_tuple_struct(input, path)?; |
| if qself.is_some() { |
| Ok(Pat::Verbatim(verbatim::between(begin, input))) |
| } else { |
| Ok(Pat::TupleStruct(pat)) |
| } |
| } else if input.peek(Token![..]) { |
| pat_range(input, begin, qself, path) |
| } else { |
| Ok(Pat::Path(PatPath { |
| attrs: Vec::new(), |
| qself, |
| path, |
| })) |
| } |
| } |
| |
| fn pat_wild(input: ParseStream) -> Result<PatWild> { |
| Ok(PatWild { |
| attrs: Vec::new(), |
| underscore_token: input.parse()?, |
| }) |
| } |
| |
| fn pat_box(input: ParseStream) -> Result<PatBox> { |
| Ok(PatBox { |
| attrs: Vec::new(), |
| box_token: input.parse()?, |
| pat: input.parse()?, |
| }) |
| } |
| |
| 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 = input.parse()?; |
| Some((at_token, Box::new(subpat))) |
| } else { |
| None |
| } |
| }, |
| }) |
| } |
| |
| fn pat_tuple_struct(input: ParseStream, path: Path) -> Result<PatTupleStruct> { |
| Ok(PatTupleStruct { |
| attrs: Vec::new(), |
| path, |
| pat: input.call(pat_tuple)?, |
| }) |
| } |
| |
| fn pat_struct(input: ParseStream, path: Path) -> Result<PatStruct> { |
| let content; |
| let brace_token = braced!(content in input); |
| |
| let mut fields = Punctuated::new(); |
| while !content.is_empty() && !content.peek(Token![..]) { |
| let value = content.call(field_pat)?; |
| fields.push_value(value); |
| if content.is_empty() { |
| break; |
| } |
| let punct: Token![,] = content.parse()?; |
| fields.push_punct(punct); |
| } |
| |
| let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) { |
| Some(content.parse()?) |
| } else { |
| None |
| }; |
| |
| Ok(PatStruct { |
| attrs: Vec::new(), |
| path, |
| brace_token, |
| fields, |
| dot2_token, |
| }) |
| } |
| |
| impl Member { |
| fn is_unnamed(&self) -> bool { |
| match *self { |
| Member::Named(_) => false, |
| Member::Unnamed(_) => true, |
| } |
| } |
| } |
| |
| fn field_pat(input: ParseStream) -> Result<FieldPat> { |
| let attrs = input.call(Attribute::parse_outer)?; |
| let boxed: Option<Token![box]> = input.parse()?; |
| let by_ref: Option<Token![ref]> = input.parse()?; |
| let mutability: Option<Token![mut]> = input.parse()?; |
| let member: Member = input.parse()?; |
| |
| if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) |
| || member.is_unnamed() |
| { |
| return Ok(FieldPat { |
| attrs, |
| member, |
| colon_token: input.parse()?, |
| pat: Box::new(multi_pat_with_leading_vert(input)?), |
| }); |
| } |
| |
| let ident = match member { |
| Member::Named(ident) => ident, |
| Member::Unnamed(_) => unreachable!(), |
| }; |
| |
| let mut pat = Pat::Ident(PatIdent { |
| attrs: Vec::new(), |
| by_ref, |
| mutability, |
| ident: ident.clone(), |
| subpat: None, |
| }); |
| |
| if let Some(boxed) = boxed { |
| pat = Pat::Box(PatBox { |
| attrs: Vec::new(), |
| box_token: boxed, |
| pat: Box::new(pat), |
| }); |
| } |
| |
| Ok(FieldPat { |
| attrs, |
| member: Member::Named(ident), |
| colon_token: None, |
| pat: Box::new(pat), |
| }) |
| } |
| |
| fn pat_range( |
| input: ParseStream, |
| begin: ParseBuffer, |
| qself: Option<QSelf>, |
| path: Path, |
| ) -> Result<Pat> { |
| let limits: RangeLimits = input.parse()?; |
| let hi = input.call(pat_lit_expr)?; |
| if let Some(hi) = hi { |
| Ok(Pat::Range(PatRange { |
| attrs: Vec::new(), |
| lo: Box::new(Expr::Path(ExprPath { |
| attrs: Vec::new(), |
| qself, |
| path, |
| })), |
| limits, |
| hi, |
| })) |
| } else { |
| Ok(Pat::Verbatim(verbatim::between(begin, input))) |
| } |
| } |
| |
| fn pat_range_half_open(input: ParseStream, begin: ParseBuffer) -> Result<Pat> { |
| let limits: RangeLimits = input.parse()?; |
| let hi = input.call(pat_lit_expr)?; |
| if hi.is_some() { |
| Ok(Pat::Verbatim(verbatim::between(begin, input))) |
| } 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_tuple(input: ParseStream) -> Result<PatTuple> { |
| let content; |
| let paren_token = parenthesized!(content in input); |
| |
| let mut elems = Punctuated::new(); |
| while !content.is_empty() { |
| let value = multi_pat_with_leading_vert(&content)?; |
| elems.push_value(value); |
| if content.is_empty() { |
| break; |
| } |
| let punct = content.parse()?; |
| elems.push_punct(punct); |
| } |
| |
| Ok(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: input.parse()?, |
| }) |
| } |
| |
| fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { |
| let begin = input.fork(); |
| let lo = input.call(pat_lit_expr)?.unwrap(); |
| if input.peek(Token![..]) { |
| let limits: RangeLimits = input.parse()?; |
| let hi = input.call(pat_lit_expr)?; |
| if let Some(hi) = hi { |
| Ok(Pat::Range(PatRange { |
| attrs: Vec::new(), |
| lo, |
| limits, |
| hi, |
| })) |
| } else { |
| Ok(Pat::Verbatim(verbatim::between(begin, input))) |
| } |
| } else if let Expr::Verbatim(verbatim) = *lo { |
| Ok(Pat::Verbatim(verbatim)) |
| } else { |
| Ok(Pat::Lit(PatLit { |
| attrs: Vec::new(), |
| expr: lo, |
| })) |
| } |
| } |
| |
| fn pat_lit_expr(input: ParseStream) -> Result<Option<Box<Expr>>> { |
| if input.is_empty() |
| || input.peek(Token![|]) |
| || input.peek(Token![=>]) |
| || input.peek(Token![:]) && !input.peek(Token![::]) |
| || input.peek(Token![,]) |
| || input.peek(Token![;]) |
| { |
| return Ok(None); |
| } |
| |
| let neg: Option<Token![-]> = input.parse()?; |
| |
| let lookahead = input.lookahead1(); |
| let expr = if lookahead.peek(Lit) { |
| Expr::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]) |
| { |
| Expr::Path(input.parse()?) |
| } else if lookahead.peek(Token![const]) { |
| Expr::Verbatim(input.call(expr::parsing::expr_const)?) |
| } else { |
| return Err(lookahead.error()); |
| }; |
| |
| Ok(Some(Box::new(if let Some(neg) = neg { |
| Expr::Unary(ExprUnary { |
| attrs: Vec::new(), |
| op: UnOp::Neg(neg), |
| expr: Box::new(expr), |
| }) |
| } else { |
| 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 = multi_pat_with_leading_vert(&content)?; |
| 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)) |
| } |
| |
| pub fn multi_pat(input: ParseStream) -> Result<Pat> { |
| multi_pat_impl(input, None) |
| } |
| |
| pub fn multi_pat_with_leading_vert(input: ParseStream) -> Result<Pat> { |
| 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 = input.parse()?; |
| 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 = input.parse()?; |
| cases.push_value(pat); |
| } |
| pat = Pat::Or(PatOr { |
| attrs: Vec::new(), |
| leading_vert, |
| cases, |
| }); |
| } |
| Ok(pat) |
| } |
| } |
| |
| #[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 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 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 PatStruct { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.path.to_tokens(tokens); |
| 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.dot2_token.is_some() { |
| <Token![,]>::default().to_tokens(tokens); |
| } |
| self.dot2_token.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()); |
| self.path.to_tokens(tokens); |
| self.pat.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 PatPath { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| private::print_path(tokens, &self.qself, &self.path); |
| } |
| } |
| |
| #[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 PatBox { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.box_token.to_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 PatLit { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.expr.to_tokens(tokens); |
| } |
| } |
| |
| #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] |
| impl ToTokens for PatRange { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.lo.to_tokens(tokens); |
| match &self.limits { |
| RangeLimits::HalfOpen(t) => t.to_tokens(tokens), |
| RangeLimits::Closed(t) => t.to_tokens(tokens), |
| } |
| self.hi.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 PatMacro { |
| fn to_tokens(&self, tokens: &mut TokenStream) { |
| tokens.append_all(self.attrs.outer()); |
| self.mac.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 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); |
| } |
| } |
| } |