ast: Add Visitor interface
Questions: do we need this?
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
pub mod macro_matcher;
|
||||
|
||||
pub mod visit;
|
||||
|
||||
/// A value with an annotation.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Anno<T: Annotation, A: Annotation = Span>(pub T, pub A);
|
||||
|
||||
263
src/ast/visit.rs
Normal file
263
src/ast/visit.rs
Normal file
@@ -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<A: Annotation>(&mut self, item: &'a Bind<A>) -> Result<(), Self::Error> {
|
||||
item.children(self)
|
||||
}
|
||||
fn visit_make<A: Annotation>(&mut self, item: &'a Make<A>) -> Result<(), Self::Error> {
|
||||
item.children(self)
|
||||
}
|
||||
fn visit_makearm<A: Annotation>(&mut self, item: &'a MakeArm<A>) -> Result<(), Self::Error> {
|
||||
item.children(self)
|
||||
}
|
||||
fn visit_expr<A: Annotation>(&mut self, expr: &'a Expr<A>) -> Result<(), Self::Error> {
|
||||
expr.children(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Walk<'a> {
|
||||
#[inline]
|
||||
fn children<V: Visit<'a> + ?Sized>(&'a self, _v: &mut V) -> Result<(), V::Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn visit_in<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error>;
|
||||
}
|
||||
|
||||
impl<'a> Walk<'a> for str {
|
||||
fn visit_in<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_ident(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Walk<'a> for FqPath {
|
||||
fn visit_in<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_path(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Walk<'a> for Literal {
|
||||
fn visit_in<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_literal(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Walk<'a> for Use {
|
||||
fn children<V: Visit<'a> + ?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<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_use(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Walk<'a> for Pat {
|
||||
fn children<V: Visit<'a> + ?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<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_pat(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Annotation> Walk<'a> for Bind<A> {
|
||||
fn children<V: Visit<'a> + ?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<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_bind(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Annotation> Walk<'a> for Make<A> {
|
||||
fn children<V: Visit<'a> + ?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<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_make(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Annotation> Walk<'a> for MakeArm<A> {
|
||||
fn children<V: Visit<'a> + ?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<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
v.visit_makearm(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Annotation> Walk<'a> for Expr<A> {
|
||||
fn children<V: Visit<'a> + ?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<V: Visit<'a> + ?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<T, A> {
|
||||
#[inline]
|
||||
fn children<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
self.0.children(v)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_in<V: Visit<'a> + ?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<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
for item in self {
|
||||
item.visit_in(v)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_in<V: Visit<'a> + ?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<T> {
|
||||
fn children<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
self.as_slice().children(v)
|
||||
}
|
||||
|
||||
fn visit_in<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
self.as_slice().visit_in(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Walk<'a>> Walk<'a> for Option<T> {
|
||||
fn children<V: Visit<'a> + ?Sized>(&'a self, v: &mut V) -> Result<(), V::Error> {
|
||||
match self {
|
||||
Some(t) => t.children(v),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
fn visit_in<V: Visit<'a> + ?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<V: VisitMut<'a> + ?Sized>(&'a mut self, v: &mut V);
|
||||
// fn visit_in_mut<V: VisitMut<'a> + ?Sized>(&'a mut self, v: &mut V);
|
||||
// }
|
||||
Reference in New Issue
Block a user