Update how visitors work, add NameId type
* Visitors are now defined on a per-type level, allowing for greater flexibility in combining and re-using behavior * NameId is used for namespaces, which are used to index locally scoped variables. Syms are used for free namespaces, specifically in objects. All NameIDs are symbols, while not all symbols are NameIDs. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,29 +1,91 @@
|
||||
use crate::syn::ast::{Stmt, Expr};
|
||||
use crate::syn::ast::prelude::*;
|
||||
|
||||
pub trait Visit {
|
||||
pub trait Visit<A: Accept> {
|
||||
type Out;
|
||||
fn visit<A: Accept<Self>>(&mut self, acceptor: &A) -> Self::Out
|
||||
where Self: Sized
|
||||
{
|
||||
acceptor.accept(self)
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &Stmt) -> Self::Out;
|
||||
fn visit_expr(&mut self, expr: &Expr) -> Self::Out;
|
||||
fn visit(&mut self, acceptor: &A) -> Self::Out;
|
||||
}
|
||||
|
||||
pub trait Accept<V: Visit> {
|
||||
fn accept(&self, visitor: &mut V) -> V::Out;
|
||||
pub trait Accept {
|
||||
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<V: Visit> Accept<V> for Stmt {
|
||||
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit_stmt(self)
|
||||
pub trait DefaultAccept<V: Visit<Self>>: 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::compile::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::compile::visit::Visit<$default> for $visitor {
|
||||
type Out = ();
|
||||
fn visit(&mut self, _: &$default) -> Self::Out {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Visit> Accept<V> for Expr {
|
||||
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit_expr(self)
|
||||
}
|
||||
macro_rules! impl_accept {
|
||||
($what:ident) => {
|
||||
impl crate::compile::visit::Accept for $what {
|
||||
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_default_accept {
|
||||
($what:ident : $($requires:ident),+ => $($tail:tt)+) => {
|
||||
impl<V, Out> DefaultAccept<V> for $what
|
||||
where V: Visit<Self, Out=Out> $(+ 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);
|
||||
|
||||
Reference in New Issue
Block a user