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:
2020-05-20 14:41:12 -04:00
parent 3ce7384f15
commit 32591f5e29
15 changed files with 306 additions and 206 deletions

View File

@@ -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);