//! Implements pattern matching use super::*; use std::collections::HashMap; /// Stores a substitution from meta-identifiers to values #[derive(Clone, Debug)] pub struct Subst { pub exp: HashMap>, pub pat: HashMap, } impl Default for Subst { fn default() -> Self { Self { exp: Default::default(), pat: Default::default() } } } impl Subst { fn add_pat(&mut self, name: String, pat: &Pat) -> bool { if self.exp.contains_key(&name) { return false; } if let Some(entry) = self.pat.get(&name) { return entry == pat; } self.pat.insert(name, pat.clone()).is_none() } fn add_expr(&mut self, name: String, exp: &Expr) -> bool { if self.pat.contains_key(&name) { return false; } if let Some(entry) = self.exp.get(&name) { return entry == exp; } self.exp.insert(name, exp.clone()).is_none() } } pub trait Match { /// Applies a substitution rule from `pat` to `template` on `self` fn apply_rule(&mut self, pat: &Self, template: &Self) -> bool where Self: Sized + Clone { let Some(sub) = self.construct(pat) else { return false; }; *self = template.clone(); self.apply(&sub); true } /// With self as the pattern, recursively applies the Subst fn apply(&mut self, sub: &Subst); /// Implements recursive Subst-building for Self fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool; /// Constructs a Subst fn construct(&self, pat: &Self) -> Option> { let mut sub = Subst::default(); Match::recurse(&mut sub, pat, self).then_some(sub) } /// Matches self against the provided pattern fn match_with(&self, pat: &Self, sub: &mut Subst) -> bool { Match::recurse(sub, pat, self) } } impl + Annotation, A: Annotation> Match for Anno { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { Match::recurse(sub, &pat.0, &expr.0) } fn apply(&mut self, sub: &Subst) { self.0.apply(sub); } } impl Match for Bind { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(pat_kind, pat_pat, pat_expr), Self(expr_kind, expr_pat, expr_expr)) = (pat, expr); pat_kind == expr_kind && Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr) } fn apply(&mut self, sub: &Subst) { let Self(_, pat, expr) = self; pat.apply(sub); expr.apply(sub); } } impl Match for crate::ast::Make { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Make(pat, pat_arms), Make(expr, expr_arms)) = (pat, expr); Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms) } fn apply(&mut self, sub: &Subst) { let Make(expr, make_arms) = self; expr.apply(sub); make_arms.apply(sub); } } impl Match for Typedef { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(pat_kind, pat_pat), Self(expr_kind, expr_pat)) = (pat, expr); pat_kind == expr_kind && Match::recurse(sub, pat_pat, expr_pat) } fn apply(&mut self, sub: &Subst) { let Self(_, pat) = self; pat.apply(sub); } } impl Match for Expr { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { match (pat, expr) { (Expr::MetId(name), _) if name == "_" => true, (Expr::MetId(name), _) => sub.add_expr(name.clone(), expr), (Expr::Id(pat), Expr::Id(expr)) => pat == expr, (Expr::Id(_), _) => false, (Expr::Lit(pat), Expr::Lit(expr)) => pat == expr, (Expr::Lit(_), _) => false, (Expr::Use(_), Expr::Use(_)) => true, (Expr::Use(_), _) => false, (Expr::Bind(pat), Expr::Bind(expr)) => Match::recurse(sub, pat, expr), (Expr::Bind(..), _) => false, (Expr::Struct(pat), Expr::Struct(expr)) => Match::recurse(sub, pat, expr), (Expr::Struct(_), _) => false, (Expr::Make(pat), Expr::Make(expr)) => Match::recurse(sub, pat, expr), (Expr::Make(..), _) => false, (Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => { Match::recurse(sub, pat_op, expr_op) && Match::recurse(sub, pat_exprs, expr_exprs) } (Expr::Op(..), _) => false, } } fn apply(&mut self, sub: &Subst) { match self { Expr::MetId(id) => { if let Some(expr) = sub.exp.get(id) { *self = expr.clone() } } Expr::Id(_) | Expr::Lit(_) | Expr::Use(_) => {} Expr::Bind(expr) => expr.apply(sub), Expr::Struct(expr) => expr.apply(sub), Expr::Make(expr) => expr.apply(sub), Expr::Op(op, exprs) => { op.apply(sub); exprs.apply(sub); } }; } } impl Match for MakeArm { // TODO: order-independent matching for MakeArm specifically. fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { pat.0 == expr.0 && Match::recurse(sub, &pat.1, &expr.1) } fn apply(&mut self, sub: &Subst) { let Self(_, expr) = self; expr.apply(sub); } } impl Match for Pat { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { match (pat, expr) { (Pat::MetId(name), _) if name == "_" => true, (Pat::MetId(name), _) => sub.add_pat(name.clone(), expr), (Pat::Ignore, Pat::Ignore) => true, (Pat::Ignore, _) => false, (Pat::Never, Pat::Never) => true, (Pat::Never, _) => false, (Pat::Name(pat), Pat::Name(expr)) => pat == expr, (Pat::Name(_), _) => false, (Pat::Path(_), Pat::Path(_)) => true, (Pat::Path(_), _) => false, (Pat::NamedStruct(_, pat), Pat::NamedStruct(_, expr)) => Match::recurse(sub, pat, expr), (Pat::NamedStruct(..), _) => false, (Pat::NamedTuple(_, pat), Pat::NamedTuple(_, expr)) => Match::recurse(sub, pat, expr), (Pat::NamedTuple(..), _) => false, (Pat::Lit(pat), Pat::Lit(expr)) => pat == expr, (Pat::Lit(_), _) => false, (Pat::Op(_, pat), Pat::Op(_, expr)) => Match::recurse(sub, pat, expr), (Pat::Op(..), _) => false, } } fn apply(&mut self, sub: &Subst) { match self { Pat::Ignore | Pat::Never | Pat::Name(_) | Pat::Path(_) | Pat::Lit(_) => {} Pat::MetId(id) => { if let Some(expr) = sub.pat.get(id) { *self = expr.clone() } } Pat::NamedStruct(_, expr) => expr.apply(sub), Pat::NamedTuple(_, expr) => expr.apply(sub), Pat::Op(_, pats) => pats.apply(sub), } } } impl Match for Op { fn recurse(_: &mut Subst, pat: &Self, expr: &Self) -> bool { pat == expr } fn apply(&mut self, _sub: &Subst) {} } impl> Match for [T] { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { if pat.len() != expr.len() { return false; } for (pat, expr) in pat.iter().zip(expr.iter()) { if !Match::recurse(sub, pat, expr) { return false; } } true } fn apply(&mut self, sub: &Subst) { for item in self { item.apply(sub); } } } impl> Match for Box { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { Match::recurse(sub, pat.as_ref(), expr.as_ref()) } fn apply(&mut self, sub: &Subst) { self.as_mut().apply(sub); } } impl> Match for Vec { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { Match::recurse(sub, pat.as_slice(), expr.as_slice()) } fn apply(&mut self, sub: &Subst) { self.as_mut_slice().apply(sub); } } impl> Match for Option { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { match (pat, expr) { (Some(pat), Some(expr)) => Match::recurse(sub, pat, expr), (None, None) => true, _ => false, } } fn apply(&mut self, sub: &Subst) { self.as_mut_slice().apply(sub); } }