use super::{Attribute, Expr, Ident, Literal, Mutability, NodeId, Path};
use crate::lexer::Span;
#[derive(Debug, Clone, PartialEq)]
pub struct Pattern {
pub kind: PatternKind,
pub span: Span,
pub id: NodeId,
}
impl Pattern {
pub fn new(kind: PatternKind, span: Span) -> Self {
Self {
kind,
span,
id: NodeId::DUMMY,
}
}
pub fn wildcard(span: Span) -> Self {
Self::new(PatternKind::Wildcard, span)
}
pub fn ident(name: Ident, mutability: Mutability) -> Self {
let span = name.span;
Self::new(
PatternKind::Ident {
mutability,
name,
subpattern: None,
},
span,
)
}
pub fn is_irrefutable(&self) -> bool {
match &self.kind {
PatternKind::Wildcard => true,
PatternKind::Ident {
subpattern: None, ..
} => true,
PatternKind::Ident {
subpattern: Some(p),
..
} => p.is_irrefutable(),
PatternKind::Tuple(patterns) => patterns.iter().all(|p| p.is_irrefutable()),
PatternKind::Ref { pattern, .. } => pattern.is_irrefutable(),
PatternKind::Paren(p) => p.is_irrefutable(),
_ => false,
}
}
pub fn binds_variables(&self) -> bool {
match &self.kind {
PatternKind::Wildcard | PatternKind::Rest => false,
PatternKind::Ident { .. } => true,
PatternKind::Literal(_) | PatternKind::Path(_) => false,
PatternKind::Tuple(patterns) | PatternKind::Slice(patterns) => {
patterns.iter().any(|p| p.binds_variables())
}
PatternKind::Struct { fields, rest, .. } => {
rest.is_some() || fields.iter().any(|f| f.pattern.binds_variables())
}
PatternKind::TupleStruct { patterns, .. } => {
patterns.iter().any(|p| p.binds_variables())
}
PatternKind::Or(patterns) => patterns.iter().any(|p| p.binds_variables()),
PatternKind::Ref { pattern, .. }
| PatternKind::Box(pattern)
| PatternKind::Paren(pattern) => pattern.binds_variables(),
PatternKind::Range { .. } => false,
PatternKind::Macro { .. } | PatternKind::Error => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum PatternKind {
Wildcard,
Rest,
Ident {
mutability: Mutability,
name: Ident,
subpattern: Option<Box<Pattern>>,
},
Literal(Literal),
Path(Path),
Tuple(Vec<Pattern>),
Slice(Vec<Pattern>),
Struct {
path: Path,
fields: Vec<FieldPattern>,
rest: Option<Span>,
},
TupleStruct { path: Path, patterns: Vec<Pattern> },
Or(Vec<Pattern>),
Ref {
mutability: Mutability,
pattern: Box<Pattern>,
},
Box(Box<Pattern>),
Range {
start: Option<Box<Expr>>,
end: Option<Box<Expr>>,
inclusive: bool,
},
Paren(Box<Pattern>),
Macro {
path: Path,
tokens: Vec<super::TokenTree>,
},
Error,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FieldPattern {
pub attrs: Vec<Attribute>,
pub name: Ident,
pub pattern: Pattern,
pub is_shorthand: bool,
pub span: Span,
}
impl FieldPattern {
pub fn shorthand(name: Ident) -> Self {
let span = name.span;
Self {
attrs: Vec::new(),
pattern: Pattern::ident(name.clone(), Mutability::Immutable),
name,
is_shorthand: true,
span,
}
}
pub fn explicit(name: Ident, pattern: Pattern) -> Self {
let span = name.span.merge(&pattern.span);
Self {
attrs: Vec::new(),
name,
pattern,
is_shorthand: false,
span,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lexer::Span;
#[test]
fn test_irrefutable() {
let span = Span::dummy();
assert!(Pattern::wildcard(span).is_irrefutable());
let ident = Ident::dummy("x");
assert!(Pattern::ident(ident, Mutability::Immutable).is_irrefutable());
let lit = Pattern::new(
PatternKind::Literal(Literal::Int {
value: 42,
suffix: None,
base: crate::lexer::IntBase::Decimal,
}),
span,
);
assert!(!lit.is_irrefutable());
}
}