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
/// `::B::C` and `::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,
pub box_token: Token![box],
pub pat: Box,
}
}
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,
pub by_ref: Option,
pub mutability: Option,
pub ident: Ident,
pub subpat: Option<(Token![@], Box)>,
}
}
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,
pub expr: Box,
}
}
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,
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,
pub leading_vert: Option,
pub cases: Punctuated,
}
}
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
/// `::B::C` and `::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,
pub qself: Option,
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,
pub lo: Box,
pub limits: RangeLimits,
pub hi: Box,
}
}
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,
pub and_token: Token![&],
pub mutability: Option,
pub pat: Box,
}
}
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,
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,
pub bracket_token: token::Bracket,
pub elems: Punctuated,
}
}
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,
pub path: Path,
pub brace_token: token::Brace,
pub fields: Punctuated,
pub dot2_token: Option,
}
}
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,
pub paren_token: token::Paren,
pub elems: Punctuated,
}
}
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,
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,
pub pat: Box,
pub colon_token: Token![:],
pub ty: Box,
}
}
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,
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,
pub member: Member,
pub colon_token: Option,
pub pat: Box,
}
}
#[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 {
let begin = input.fork();
let lookahead = input.lookahead1();
if {
let ahead = input.fork();
ahead.parse::