diff --git a/src/ast.rs b/src/ast.rs index 042c4b9..76efe97 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2,6 +2,8 @@ pub mod macro_matcher; +pub mod visit; + /// A value with an annotation. #[derive(Clone, PartialEq, Eq)] pub struct Anno(pub T, pub A); diff --git a/src/ast/visit.rs b/src/ast/visit.rs new file mode 100644 index 0000000..5fb968b --- /dev/null +++ b/src/ast/visit.rs @@ -0,0 +1,263 @@ +//! AST visitor +#![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::wildcard_imports, clippy::missing_errors_doc)] +use super::*; + +pub trait Visit<'a> { + type Error; + + fn visit(&mut self, walk: &'a impl Walk<'a>) -> Result<(), Self::Error> { + walk.visit_in(self) + } + fn visit_ident(&mut self, name: &'a str) -> Result<(), Self::Error> { + name.children(self) + } + fn visit_path(&mut self, path: &'a FqPath) -> Result<(), Self::Error> { + path.children(self) + } + fn visit_literal(&mut self, lit: &'a Literal) -> Result<(), Self::Error> { + lit.children(self) + } + fn visit_use(&mut self, item: &'a Use) -> Result<(), Self::Error> { + item.children(self) + } + fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> { + item.children(self) + } + fn visit_bind(&mut self, item: &'a Bind) -> Result<(), Self::Error> { + item.children(self) + } + fn visit_make(&mut self, item: &'a Make) -> Result<(), Self::Error> { + item.children(self) + } + fn visit_makearm(&mut self, item: &'a MakeArm) -> Result<(), Self::Error> { + item.children(self) + } + fn visit_expr(&mut self, expr: &'a Expr) -> Result<(), Self::Error> { + expr.children(self) + } +} + +pub trait Walk<'a> { + #[inline] + fn children + ?Sized>(&'a self, _v: &mut V) -> Result<(), V::Error> { + Ok(()) + } + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error>; +} + +impl<'a> Walk<'a> for str { + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_ident(self) + } +} + +impl<'a> Walk<'a> for FqPath { + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_path(self) + } +} + +impl<'a> Walk<'a> for Literal { + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_literal(self) + } +} + +impl<'a> Walk<'a> for Use { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + match self { + Self::Glob => Ok(()), + Self::Name(name) => name.visit_in(v), + Self::Path(name, rest) => { + name.visit_in(v)?; + rest.visit_in(v) + } + Self::Tree(items) => items.visit_in(v), + } + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_use(self) + } +} + +impl<'a> Walk<'a> for Pat { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + match self { + Self::Ignore | Self::Never => Ok(()), + Self::MetId(id) => id.visit_in(v), + Self::Name(name) => name.visit_in(v), + Self::Path(path) => path.visit_in(v), + Self::NamedStruct(path, pat) | Self::NamedTuple(path, pat) => { + path.visit_in(v)?; + pat.visit_in(v) + } + Self::Lit(literal) => literal.visit_in(v), + Self::Op(_, pats) => pats.visit_in(v), + } + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_pat(self) + } +} + +impl<'a, A: Annotation> Walk<'a> for Bind { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + let Self(_kind, gens, pat, exprs) = self; + gens.visit_in(v)?; + pat.visit_in(v)?; + exprs.visit_in(v) + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_bind(self) + } +} + +impl<'a, A: Annotation> Walk<'a> for Make { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + let Self(expr, arms) = self; + expr.visit_in(v)?; + arms.visit_in(v) + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_make(self) + } +} + +impl<'a, A: Annotation> Walk<'a> for MakeArm { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + let Self(name, expr) = self; + name.visit_in(v)?; + expr.visit_in(v) + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_makearm(self) + } +} + +impl<'a, A: Annotation> Walk<'a> for Expr { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + match self { + Self::Omitted => Ok(()), + Self::Id(path) => path.visit_in(v), + Self::MetId(id) => id.visit_in(v), + Self::Lit(literal) => literal.visit_in(v), + Self::Use(u) => u.visit_in(v), + Self::Bind(bind) => bind.visit_in(v), + Self::Make(make) => make.visit_in(v), + Self::Op(_op, annos) => annos.visit_in(v), + } + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + v.visit_expr(self) + } +} + +impl<'a, T: Annotation + Walk<'a>, A: Annotation> Walk<'a> for Anno { + #[inline] + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + self.0.children(v) + } + + #[inline] + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + self.0.visit_in(v) + } +} + +////////////////////////////////////////////// +// GENERIC IMPLEMENTATIONS ON COLLECTIONS // +////////////////////////////////////////////// + +impl<'a, T: Walk<'a>> Walk<'a> for [T] { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + for item in self { + item.visit_in(v)?; + } + Ok(()) + } + + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + for item in self { + item.visit_in(v)?; + } + Ok(()) + } +} + +impl<'a, T: Walk<'a>> Walk<'a> for Vec { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + self.as_slice().children(v) + } + + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + self.as_slice().visit_in(v) + } +} + +impl<'a, T: Walk<'a>> Walk<'a> for Option { + fn children + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + match self { + Some(t) => t.children(v), + _ => Ok(()), + } + } + fn visit_in + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> { + match self { + Some(t) => t.visit_in(v), + _ => Ok(()), + } + } +} + +// pub trait VisitMut<'a> { +// fn visit_mut(&mut self, walk: &'a mut impl WalkMut<'a>) { +// walk.visit_in_mut(self); +// } +// fn visit_ident_mut(&mut self, name: &'a mut str) { +// name.children_mut(self); +// } +// fn visit_path_mut(&mut self, walk: &'a FqPath) { +// walk.children_mut(self); +// } +// fn visit_literal_mut(&mut self, walk: &'a Literal) { +// walk.children_mut(self); +// } +// fn visit_use_mut(&mut self, walk: &'a Use) { +// walk.children_mut(self); +// } +// fn visit_pat_mut(&mut self, walk: &'a Pat) { +// walk.children_mut(self); +// } +// fn visit_bind_mut(&mut self, walk: &'a Bind) { +// walk.children_mut(self); +// } +// fn visit_make_mut(&mut self, walk: &'a Make) { +// walk.children_mut(self); +// } +// fn visit_makearm_mut(&mut self, walk: &'a MakeArm) { +// walk.children_mut(self); +// } +// fn visit_typedef_mut(&mut self, walk: &'a Typedef) { +// walk.children_mut(self); +// } +// fn visit_expr_mut(&mut self, walk: &'a Expr) { +// walk.children_mut(self); +// } +// } +// pub trait WalkMut<'a> { +// fn children_mut + ?Sized>(&'a mut self, v: &mut V); +// fn visit_in_mut + ?Sized>(&'a mut self, v: &mut V); +// }