use crate::syn::ast::prelude::*; pub trait Visit { type Out; fn visit(&mut self, acceptor: &A) -> Self::Out; } pub trait Accept { fn accept>(&self, visitor: &mut V) -> V::Out where Self: Sized; } pub trait DefaultAccept>: Accept + Sized { fn default_accept(&self, visitor: &mut V) -> V::Out; } #[macro_export] macro_rules! default_visitor { ($default:ident for $visitor:ty where Out = $out:ty) => { impl crate::visit::Visit<$default> for $visitor { type Out = $out; fn visit(&mut self, acceptor: &$default) -> Self::Out { acceptor.default_accept(self) } } }; } #[macro_export] macro_rules! empty_visitor { ($default:ident for $visitor:ty) => { impl crate::visit::Visit<$default> for $visitor { type Out = (); fn visit(&mut self, _: &$default) -> Self::Out {} } }; } macro_rules! impl_accept { ($what:ident) => { impl crate::visit::Accept for $what { fn accept>(&self, visitor: &mut V) -> V::Out { visitor.visit(self) } } }; } macro_rules! impl_default_accept { ($what:ident : $($requires:ident),+ => $($tail:tt)+) => { impl DefaultAccept for $what where V: Visit $(+ Visit<$requires, Out=Out>)+ { $($tail)+ } }; } impl_accept!(Stmt); impl_default_accept!(Stmt : AssignStmt, Expr => fn default_accept(&self, visitor: &mut V) -> Out { match self { Stmt::Assign(a) => visitor.visit(a), Stmt::Expr(e) => visitor.visit(e), } } ); impl_accept!(AssignStmt); impl_accept!(Expr); impl_default_accept!(Expr: BinExpr, UnExpr, FunCallExpr, IndexExpr, FunExpr, BaseExpr => fn default_accept(&self, visitor: &mut V) -> Out { match self { Expr::Bin(b) => visitor.visit(b.as_ref()), Expr::Un(u) => visitor.visit(u.as_ref()), Expr::FunCall(f) => visitor.visit(f.as_ref()), Expr::Index(i) => visitor.visit(i.as_ref()), Expr::Fun(f) => visitor.visit(f.as_ref()), Expr::Base(b) => visitor.visit(b), } } ); impl_accept!(BinExpr); impl_accept!(UnExpr); impl_accept!(FunCallExpr); impl_accept!(IndexExpr); impl_accept!(FunExpr); impl_accept!(BaseExpr);