From b9085551e12d57451f7529ee676545dffbce2d9d Mon Sep 17 00:00:00 2001 From: John Date: Sat, 27 Apr 2024 15:51:37 -0500 Subject: [PATCH] cl-typeck: Reimplement NameCollectable in terms of an AST visitor --- compiler/cl-typeck/src/name_collector.rs | 339 +++++++++-------------- 1 file changed, 131 insertions(+), 208 deletions(-) diff --git a/compiler/cl-typeck/src/name_collector.rs b/compiler/cl-typeck/src/name_collector.rs index 6a77113..67cae54 100644 --- a/compiler/cl-typeck/src/name_collector.rs +++ b/compiler/cl-typeck/src/name_collector.rs @@ -5,7 +5,8 @@ use crate::{ module::Module as Mod, project::Project as Prj, }; -use cl_ast::*; +use cl_ast::{ast_visitor::Visit, *}; +use std::mem; pub trait NameCollectable<'a> { /// Collects the identifiers within this node, @@ -19,227 +20,149 @@ pub trait NameCollectable<'a> { } impl<'a> NameCollectable<'a> for File { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - for item in &self.items { - item.collect(c, parent)?; - } + fn collect(&'a self, prj: &mut Prj<'a>, parent: DefID) -> Result { + NameCollector::with_root(prj, parent).visit_file(self); Ok(parent) } } -impl<'a> NameCollectable<'a> for Item { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Item { attrs: Attrs { meta }, vis, kind, .. } = self; - let id = match kind { - ItemKind::Impl(i) => i.collect(c, parent), - ItemKind::Module(i) => i.collect(c, parent), - ItemKind::Alias(i) => i.collect(c, parent), - ItemKind::Enum(i) => i.collect(c, parent), - ItemKind::Struct(i) => i.collect(c, parent), - ItemKind::Const(i) => i.collect(c, parent), - ItemKind::Static(i) => i.collect(c, parent), - ItemKind::Function(i) => i.collect(c, parent), - ItemKind::Use(i) => i.collect(c, parent), - }?; - c[id].set_meta(meta).set_vis(*vis).set_source(self); - Ok(id) +#[derive(Debug)] +pub struct NameCollector<'prj, 'a> { + prj: &'prj mut Prj<'a>, + parent: DefID, + retval: Option, +} + +impl<'prj, 'a> NameCollector<'prj, 'a> { + pub fn new(prj: &'prj mut Prj<'a>) -> Self { + Self { parent: prj.root, prj, retval: None } + } + pub fn with_root(prj: &'prj mut Prj<'a>, parent: DefID) -> Self { + Self { prj, parent, retval: None } + } + /// Runs the provided function with the given parent + pub fn with_parent(&mut self, parent: DefID, node: N, f: F) + where F: FnOnce(&mut Self, N) { + let parent = mem::replace(&mut self.parent, parent); + f(self, node); + self.parent = parent; + } + /// Extracts the return value from the provided function + pub fn returns(&mut self, node: N, f: F) -> Option + where F: FnOnce(&mut Self, N) { + let out = self.retval.take(); + f(self, node); + mem::replace(&mut self.retval, out) } } -impl<'a> NameCollectable<'a> for Module { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Self { name: Identifier(name), kind } = self; - let module = - c.pool - .insert(Def { name: *name, module: Mod::new(parent), ..Default::default() }); - c[parent].module.types.insert(*name, module); - match kind { - ModuleKind::Inline(file) => file.collect(c, module)?, - ModuleKind::Outline => todo!("Out of line modules: {name}"), - }; - Ok(module) +impl<'prj, 'a> ast_visitor::Visit<'a> for NameCollector<'prj, 'a> { + fn visit_item(&mut self, i: &'a Item) { + let Item { extents: _, attrs, vis, kind } = i; + if let Some(def) = self.returns(kind, Self::visit_item_kind) { + self.prj[def] + .set_meta(&attrs.meta) + .set_vis(*vis) + .set_source(i); + } } -} -impl<'a> NameCollectable<'a> for Impl { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Self { target: _, body } = self; - let def = Def { module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); + fn visit_module(&mut self, m: &'a Module) { + let Self { prj, parent, retval: _ } = self; + let Module { name: Identifier(name), kind } = m; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.types.insert(*name, id); + + self.with_parent(id, kind, Self::visit_module_kind); + self.retval = Some(id); + } + fn visit_alias(&mut self, a: &'a Alias) { + let Self { prj, parent, retval: _ } = self; + let Alias { to: Identifier(name), from: _ } = a; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.types.insert(*name, id); + + self.retval = Some(id); + } + fn visit_enum(&mut self, e: &'a Enum) { + let Self { prj, parent, retval: _ } = self; + let Enum { name: Identifier(name), kind } = e; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.types.insert(*name, id); + + self.with_parent(id, kind, Self::visit_enum_kind); + self.retval = Some(id); + } + fn visit_struct(&mut self, s: &'a Struct) { + let Self { prj, parent, retval: _ } = self; + let Struct { name: Identifier(name), kind } = s; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.types.insert(*name, id); + + self.with_parent(id, kind, Self::visit_struct_kind); + self.retval = Some(id); + } + fn visit_const(&mut self, c: &'a Const) { + let Self { prj, parent, retval: _ } = self; + let Const { name: Identifier(name), ty: _, init } = c; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.values.insert(*name, id); + + self.with_parent(id, &**init, Self::visit_expr); + self.retval = Some(id); + } + fn visit_static(&mut self, s: &'a Static) { + let Self { prj, parent, retval: _ } = self; + let Static { name: Identifier(name), mutable: _, ty: _, init } = s; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.values.insert(*name, id); + + self.with_parent(id, &**init, Self::visit_expr); + self.retval = Some(id); + } + fn visit_function(&mut self, f: &'a Function) { + let Self { prj, parent, retval: _ } = self; + let Function { name: Identifier(name), body, .. } = f; + + let def = Def { name: *name, module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); + prj[*parent].module.values.insert(*name, id); + + if let Some(body) = body { + self.with_parent(id, body, Self::visit_block); + } + self.retval = Some(id); + } + fn visit_impl(&mut self, i: &'a Impl) { + let Self { prj, parent, retval: _ } = self; + let Impl { target: _, body } = i; + let def = Def { module: Mod::new(*parent), ..Default::default() }; + let id = prj.pool.insert(def); // items will get reparented after name collection, when target is available - body.collect(c, id)?; + self.with_parent(id, body, Self::visit_file); - Ok(id) + self.retval = Some(id); } -} -impl<'a> NameCollectable<'a> for Use { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { + fn visit_use(&mut self, _u: &'a Use) { + let Self { prj, parent, retval } = self; let def = - Def { module: Mod::new(parent), kind: DefKind::Use(parent), ..Default::default() }; + Def { module: Mod::new(*parent), kind: DefKind::Use(*parent), ..Default::default() }; - let id = c.pool.insert(def); - c[parent].module.imports.push(id); + let id = prj.pool.insert(def); + prj[*parent].module.imports.push(id); - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Alias { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Alias { to: Identifier(name), .. } = self; - - let def = Def { name: *name, module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); - - c[parent].module.types.insert(*name, id); - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Enum { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Enum { name: Identifier(name), .. } = self; - - let def = Def { name: *name, module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); - - c[parent].module.types.insert(*name, id); - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Struct { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Struct { name: Identifier(name), .. } = self; - - let def = Def { name: *name, module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); - - c[parent].module.types.insert(*name, id); - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Const { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Self { name: Identifier(name), init, .. } = self; - - let kind = DefKind::Undecided; - - let def = Def { name: *name, kind, module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); - - c[parent].module.values.insert(*name, id); - init.collect(c, id)?; - - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Static { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Self { name: Identifier(name), init, .. } = self; - - let kind = DefKind::Undecided; - - let def = Def { name: *name, kind, module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); - - c[parent].module.values.insert(*name, id); - init.collect(c, id)?; - - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Function { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let Self { name: Identifier(name), body, .. } = self; - - let kind = DefKind::Undecided; - - let def = Def { name: *name, kind, module: Mod::new(parent), ..Default::default() }; - let id = c.pool.insert(def); - - c[parent].module.values.insert(*name, id); - body.collect(c, id)?; - - Ok(id) - } -} -impl<'a> NameCollectable<'a> for Block { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - self.stmts.as_slice().collect(c, parent) - } -} -impl<'a> NameCollectable<'a> for Stmt { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - self.kind.collect(c, parent) - } -} -impl<'a> NameCollectable<'a> for StmtKind { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - match self { - StmtKind::Empty => Ok(parent), - StmtKind::Local(Let { init, .. }) => init.collect(c, parent), - StmtKind::Item(item) => item.collect(c, parent), - StmtKind::Expr(expr) => expr.collect(c, parent), - } - } -} -impl<'a> NameCollectable<'a> for Expr { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - self.kind.collect(c, parent) - } -} -impl<'a> NameCollectable<'a> for ExprKind { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - match self { - ExprKind::Assign(Assign { parts, .. }) | ExprKind::Binary(Binary { parts, .. }) => { - parts.0.collect(c, parent)?; - parts.1.collect(c, parent) - } - ExprKind::Unary(Unary { tail, .. }) => tail.collect(c, parent), - ExprKind::Index(Index { head, indices }) => { - indices.collect(c, parent)?; - head.collect(c, parent) - } - ExprKind::Array(Array { values }) => values.collect(c, parent), - ExprKind::ArrayRep(ArrayRep { value, repeat }) => { - value.collect(c, parent)?; - repeat.collect(c, parent) - } - ExprKind::AddrOf(AddrOf { expr, .. }) => expr.collect(c, parent), - ExprKind::Block(block) => block.collect(c, parent), - ExprKind::Group(Group { expr }) => expr.collect(c, parent), - ExprKind::Tuple(Tuple { exprs }) => exprs.collect(c, parent), - ExprKind::While(While { cond, pass, fail }) - | ExprKind::If(If { cond, pass, fail }) - | ExprKind::For(For { cond, pass, fail, .. }) => { - cond.collect(c, parent)?; - pass.collect(c, parent)?; - fail.body.collect(c, parent) - } - ExprKind::Break(Break { body }) | ExprKind::Return(Return { body }) => { - body.collect(c, parent) - } - _ => Ok(parent), - } - } -} -impl<'a, T: NameCollectable<'a>> NameCollectable<'a> for [T] { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - let mut last = parent; - for expr in self { - last = expr.collect(c, parent)?; - } - Ok(last) - } -} -impl<'a, T: NameCollectable<'a>> NameCollectable<'a> for Option { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - match self { - Some(body) => body.collect(c, parent), - None => Ok(parent), - } - } -} -impl<'a, T: NameCollectable<'a>> NameCollectable<'a> for Box { - fn collect(&'a self, c: &mut Prj<'a>, parent: DefID) -> Result { - (**self).collect(c, parent) + *retval = Some(id); } }