usecrate::attr::Attribute; usecrate::expr::Member; usecrate::ident::Ident; usecrate::path::{Path, QSelf}; usecrate::punctuated::Punctuated; usecrate::token; usecrate::ty::Type; use proc_macro2::TokenStream;
pubusecrate::expr::{
ExprConst as PatConst, ExprLit as PatLit, ExprMacro as PatMacro, ExprPath as PatPath,
ExprRange as PatRange,
};
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]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, doc(cfg(feature = "full")))] #[non_exhaustive] pubenum 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 { // #![cfg_attr(test, deny(non_exhaustive_omitted_patterns))] // // Pat::Box(pat) => {...} // Pat::Ident(pat) => {...} // ... // Pat::Wild(pat) => {...} // // _ => { /* 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(docsrs, doc(cfg(feature = "full")))] pubstruct 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(docsrs, doc(cfg(feature = "full")))] pubstruct PatOr { pub attrs: Vec<Attribute>, pub leading_vert: Option<Token![|]>, pub cases: Punctuated<Pat, Token![|]>,
}
}
ast_struct! { /// A pattern that matches any value: `_`. #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pubstruct 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(docsrs, doc(cfg(feature = "full")))] pubstruct FieldPat { pub attrs: Vec<Attribute>, pub member: Member, pub colon_token: Option<Token![:]>, pub pat: Box<Pat>,
}
}
#[cfg_attr(docsrs, 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)` /// ``` pubfn 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)
} elseif lookahead.peek(Token![_]) {
input.call(pat_wild).map(Pat::Wild)
} elseif input.peek(Token![box]) {
pat_box(begin, input)
} elseif input.peek(Token![-]) || lookahead.peek(Lit) || lookahead.peek(Token![const])
{
pat_lit_or_range(input)
} elseif lookahead.peek(Token![ref])
|| lookahead.peek(Token![mut])
|| input.peek(Token![self])
|| input.peek(Ident)
{
input.call(pat_ident).map(Pat::Ident)
} elseif lookahead.peek(Token![&]) {
input.call(pat_reference).map(Pat::Reference)
} elseif lookahead.peek(token::Paren) {
input.call(pat_paren_or_tuple)
} elseif lookahead.peek(token::Bracket) {
input.call(pat_slice).map(Pat::Slice)
} elseif lookahead.peek(Token![..]) && !input.peek(Token![...]) {
pat_range_half_open(input)
} elseif lookahead.peek(Token![const]) {
input.call(pat_const).map(Pat::Verbatim)
} else {
Err(lookahead.error())
}
}
/// Parse a pattern, possibly involving `|`, but not a leading `|`. pubfn 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. pubfn parse_multi_with_leading_vert(input: ParseStream) -> Result<Self> { let leading_vert: Option<Token![|]> = input.parse()?;
multi_pat_impl(input, leading_vert)
}
}
fn pat_tuple_struct(
input: ParseStream,
qself: Option<QSelf>,
path: Path,
) -> Result<PatTupleStruct> { let content; let paren_token = parenthesized!(content in input);
letmut 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);
}
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()
}?;
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for PatStruct { fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.append_all(self.attrs.outer());
path::printing::print_qpath(tokens, &self.qself, &'color:red'>self.path, PathStyle::Expr); 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(docsrs, 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); // If there is only one element, a trailing comma is needed to // distinguish PatTuple from PatParen, unless this is `(..)` // which is a tuple pattern even without comma. ifself.elems.len() == 1
&& !self.elems.trailing_punct()
&& !matches!(self.elems[0], Pat::Rest { .. })
{
<Token![,]>::default().to_tokens(tokens);
}
});
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.