matchers: rename to "macro_matchers"
This commit is contained in:
272
src/ast/macro_matcher.rs
Normal file
272
src/ast/macro_matcher.rs
Normal file
@@ -0,0 +1,272 @@
|
||||
//! Implements pattern matching
|
||||
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Stores a substitution from meta-identifiers to values
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Subst<A: Annotation> {
|
||||
pub exp: HashMap<String, Expr<A>>,
|
||||
pub pat: HashMap<String, Pat>,
|
||||
}
|
||||
|
||||
impl<A: Annotation> Default for Subst<A> {
|
||||
fn default() -> Self {
|
||||
Self { exp: Default::default(), pat: Default::default() }
|
||||
}
|
||||
}
|
||||
impl<A: Annotation> Subst<A> {
|
||||
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<A>) -> 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<A: Annotation> {
|
||||
/// 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<A>);
|
||||
|
||||
/// Implements recursive Subst-building for Self
|
||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool;
|
||||
|
||||
/// Constructs a Subst
|
||||
fn construct(&self, pat: &Self) -> Option<Subst<A>> {
|
||||
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<A>) -> bool {
|
||||
Match::recurse(sub, pat, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Match<A> + Annotation, A: Annotation> Match<A> for Anno<M, A> {
|
||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||
Match::recurse(sub, &pat.0, &expr.0)
|
||||
}
|
||||
|
||||
fn apply(&mut self, sub: &Subst<A>) {
|
||||
self.0.apply(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation> Match<A> for Expr<A> {
|
||||
fn recurse(sub: &mut Subst<A>, 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_pat, pat_expr), Expr::Let(expr_pat, expr_expr)) => {
|
||||
Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr)
|
||||
}
|
||||
(Expr::Let(..), _) => false,
|
||||
(Expr::Const(pat_pat, pat_expr), Expr::Const(expr_pat, expr_expr)) => {
|
||||
Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr)
|
||||
}
|
||||
(Expr::Const(..), _) => false,
|
||||
(Expr::Make(pat, pat_arms), Expr::Make(expr, expr_arms)) => {
|
||||
Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms)
|
||||
}
|
||||
(Expr::Make(..), _) => false,
|
||||
(Expr::Match(pat, pat_arms), Expr::Match(expr, expr_arms)) => {
|
||||
Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms)
|
||||
}
|
||||
(Expr::Match(..), _) => false,
|
||||
(Expr::Fn(pat_pats, pat_expr), Expr::Fn(expr_pats, expr_expr)) => {
|
||||
Match::recurse(sub, pat_pats, expr_pats) && Match::recurse(sub, pat_expr, expr_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<A>) {
|
||||
match self {
|
||||
Expr::MetId(id) => {
|
||||
if let Some(expr) = sub.exp.get(id) {
|
||||
*self = expr.clone()
|
||||
}
|
||||
}
|
||||
Expr::Id(_) | Expr::Lit(_) => {}
|
||||
Expr::Let(pat, expr) => {
|
||||
pat.apply(sub);
|
||||
expr.apply(sub);
|
||||
}
|
||||
Expr::Const(pat, expr) => {
|
||||
pat.apply(sub);
|
||||
expr.apply(sub);
|
||||
}
|
||||
Expr::Make(expr, make_arms) => {
|
||||
expr.apply(sub);
|
||||
make_arms.apply(sub);
|
||||
}
|
||||
Expr::Match(expr, match_arms) => {
|
||||
expr.apply(sub);
|
||||
match_arms.apply(sub);
|
||||
}
|
||||
Expr::Fn(pats, expr) => {
|
||||
pats.apply(sub);
|
||||
expr.apply(sub);
|
||||
}
|
||||
Expr::Op(op, exprs) => {
|
||||
op.apply(sub);
|
||||
exprs.apply(sub);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation> Match<A> for MakeArm<A> {
|
||||
// TODO: order-independent matching for MakeArm specifically.
|
||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||
pat.0 == expr.0 && Match::recurse(sub, &pat.1, &expr.1)
|
||||
}
|
||||
|
||||
fn apply(&mut self, sub: &Subst<A>) {
|
||||
let Self(_, expr) = self;
|
||||
expr.apply(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation> Match<A> for MatchArm<A> {
|
||||
fn recurse(sub: &mut Subst<A>, 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<A>) {
|
||||
let Self(pats, expr) = self;
|
||||
pats.apply(sub);
|
||||
expr.apply(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation> Match<A> for Pat {
|
||||
fn recurse(sub: &mut Subst<A>, 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::Rest(pat), Pat::Rest(expr)) => Match::recurse(sub, pat, expr),
|
||||
(Pat::Rest(_), _) => false,
|
||||
(Pat::Lit(pat), Pat::Lit(expr)) => pat == expr,
|
||||
(Pat::Lit(_), _) => false,
|
||||
(Pat::Tuple(pat), Pat::Tuple(expr)) => Match::recurse(sub, pat, expr),
|
||||
(Pat::Tuple(_), _) => false,
|
||||
(Pat::Slice(pat), Pat::Slice(expr)) => Match::recurse(sub, pat, expr),
|
||||
(Pat::Slice(_), _) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply(&mut self, sub: &Subst<A>) {
|
||||
match self {
|
||||
Pat::Ignore | Pat::Name(_) | Pat::Lit(_) => {}
|
||||
Pat::MetId(id) => {
|
||||
if let Some(expr) = sub.pat.get(id) {
|
||||
*self = expr.clone()
|
||||
}
|
||||
}
|
||||
Pat::Rest(pat) => pat.apply(sub),
|
||||
Pat::Tuple(pats) => pats.apply(sub),
|
||||
Pat::Slice(pats) => pats.apply(sub),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation> Match<A> for Op {
|
||||
fn recurse(_: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||
pat == expr
|
||||
}
|
||||
|
||||
fn apply(&mut self, _sub: &Subst<A>) {}
|
||||
}
|
||||
|
||||
impl<A: Annotation, T: Match<A>> Match<A> for [T] {
|
||||
fn recurse(sub: &mut Subst<A>, 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<A>) {
|
||||
for item in self {
|
||||
item.apply(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation, T: Match<A>> Match<A> for Box<T> {
|
||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||
Match::recurse(sub, pat.as_ref(), expr.as_ref())
|
||||
}
|
||||
|
||||
fn apply(&mut self, sub: &Subst<A>) {
|
||||
self.as_mut().apply(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation, T: Match<A>> Match<A> for Vec<T> {
|
||||
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
|
||||
Match::recurse(sub, pat.as_slice(), expr.as_slice())
|
||||
}
|
||||
|
||||
fn apply(&mut self, sub: &Subst<A>) {
|
||||
self.as_mut_slice().apply(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Annotation, T: Match<A>> Match<A> for Option<T> {
|
||||
fn recurse(sub: &mut Subst<A>, 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<A>) {
|
||||
self.as_mut_slice().apply(sub);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user