//! 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 Const { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(pat_pat, pat_expr), Self(expr_pat, expr_expr)) = (pat, expr); 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 Fn { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let ( Self(pat_id, pat_arg, _pat_rety, pat_body), Self(expr_id, expr_arg, _expr_rety, expr_body), ) = (pat, expr); pat_id == expr_id && Match::recurse(sub, pat_arg, expr_arg) && Match::recurse(sub, pat_body, expr_body) } fn apply(&mut self, sub: &Subst) { let Self(_, pat, _rety, body) = self; pat.apply(sub); body.apply(sub); } } impl Match for Let { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(pat_pat, pat_expr), Self(expr_pat, expr_expr)) = (pat, expr); 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::Match { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(pat_expr, pat_arms), Self(expr_expr, expr_arms)) = (pat, expr); Match::recurse(sub, pat_expr, expr_expr) && Match::recurse(sub, pat_arms, expr_arms) } 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 Mod { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(_pat_ty, pat_expr), Self(_expr_ty, expr_expr)) = (pat, expr); // TODO: unify types for ast matching // Match::recurse(sub, pat_ty, expr_ty) && Match::recurse(sub, pat_expr, expr_expr) } fn apply(&mut self, sub: &Subst) { let Mod(_ty, expr) = self; expr.apply(sub); } } impl Match for Struct { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { let (Self(pat_pat), Self(expr_pat)) = (pat, expr); 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::Let(pat), Expr::Let(expr)) => Match::recurse(sub, pat, expr), (Expr::Let(..), _) => false, (Expr::Const(pat), Expr::Const(expr)) => Match::recurse(sub, pat, expr), (Expr::Const(..), _) => 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::Match(pat), Expr::Match(expr)) => Match::recurse(sub, pat, expr), (Expr::Match(..), _) => false, (Expr::Mod(pat), Expr::Mod(expr)) => Match::recurse(sub, pat, expr), (Expr::Mod(..), _) => false, (Expr::Fn(pat), Expr::Fn(expr)) => Match::recurse(sub, pat, expr), (Expr::Fn(..), _) => 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::Let(expr) => expr.apply(sub), Expr::Const(expr) => expr.apply(sub), Expr::Struct(expr) => expr.apply(sub), Expr::Make(expr) => expr.apply(sub), Expr::Match(expr) => expr.apply(sub), Expr::Mod(expr) => expr.apply(sub), Expr::Fn(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 MatchArm { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { Match::recurse(sub, &pat.0, &expr.0) && Match::recurse(sub, &pat.1, &expr.1) } fn apply(&mut self, sub: &Subst) { let Self(pats, expr) = self; pats.apply(sub); 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::Name(pat), Pat::Name(expr)) => pat == expr, (Pat::Name(_), _) => false, (Pat::Path(_), Pat::Path(_)) => true, (Pat::Path(_), _) => false, (Pat::Struct(_, pat), Pat::Struct(_, expr)) => Match::recurse(sub, pat, expr), (Pat::Struct(..), _) => false, (Pat::TupStruct(_, pat), Pat::TupStruct(_, expr)) => Match::recurse(sub, pat, expr), (Pat::TupStruct(..), _) => false, (Pat::Lit(pat), Pat::Lit(expr)) => pat == expr, (Pat::Lit(_), _) => false, (Pat::Typed(pat, _), Pat::Typed(expr, _)) => Match::recurse(sub, pat, expr), (Pat::Typed(..), _) => 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::Name(_) | Pat::Path(_) | Pat::Lit(_) => {} Pat::MetId(id) => { if let Some(expr) = sub.pat.get(id) { *self = expr.clone() } } Pat::Struct(_, expr) => expr.apply(sub), Pat::TupStruct(_, expr) => expr.apply(sub), Pat::Typed(pat, ty) => { pat.apply(sub); ty.apply(sub); } Pat::Op(_, pats) => pats.apply(sub), } } } impl Match for Ty { fn apply(&mut self, sub: &Subst) { todo!("Apply subst {sub:?} for {self}.") } fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { todo!("Construct subst {sub:?} from {pat} and {expr}.") } } 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); } }