pub trait FindFunctionDeclaration { fn find_function_declaration(&self, name: &str, arity: usize) -> std::rc::Rc; } pub trait FindPredicateDeclaration { fn find_predicate_declaration(&self, name: &str, arity: usize) -> std::rc::Rc; } pub trait FindVariableDeclaration { fn find_variable_declaration(&self, name: &str) -> std::rc::Rc; } pub struct FreeVariableDeclarations { variable_declarations: std::cell::RefCell, } impl FreeVariableDeclarations { pub fn new() -> Self { Self { variable_declarations: std::cell::RefCell::new(vec![]), } } } pub struct BoundVariableDeclarations<'p> { parent: &'p VariableDeclarationStackLayer<'p>, variable_declarations: std::rc::Rc, } impl<'p> BoundVariableDeclarations<'p> { pub fn new(parent: &'p VariableDeclarationStackLayer<'p>, variable_declarations: std::rc::Rc) -> Self { Self { parent, variable_declarations, } } } pub enum VariableDeclarationStackLayer<'p> { Free(FreeVariableDeclarations), Bound(BoundVariableDeclarations<'p>), } impl<'p> VariableDeclarationStackLayer<'p> { pub fn free() -> Self { Self::Free(FreeVariableDeclarations::new()) } pub fn bound(parent: &'p VariableDeclarationStackLayer<'p>, variable_declarations: std::rc::Rc) -> Self { Self::Bound(BoundVariableDeclarations::new(parent, variable_declarations)) } pub fn find(&self, variable_name: &str) -> Option> { match self { VariableDeclarationStackLayer::Free(free) => { if let Some(variable_declaration) = free.variable_declarations.borrow().iter() .find(|x| x.name == variable_name) { return Some(std::rc::Rc::clone(&variable_declaration)); } None }, VariableDeclarationStackLayer::Bound(bound) => { if let Some(variable_declaration) = bound.variable_declarations.iter() .find(|x| x.name == variable_name) { return Some(std::rc::Rc::clone(&variable_declaration)); } bound.parent.find(variable_name) }, } } pub fn find_or_create(&self, variable_name: &str) -> std::rc::Rc { match self { VariableDeclarationStackLayer::Free(free) => { if let Some(variable_declaration) = free.variable_declarations.borrow().iter() .find(|x| x.name == variable_name) { return std::rc::Rc::clone(&variable_declaration); } let variable_declaration = crate::VariableDeclaration { name: variable_name.to_owned(), }; let variable_declaration = std::rc::Rc::new(variable_declaration); free.variable_declarations.borrow_mut() .push(std::rc::Rc::clone(&variable_declaration)); variable_declaration }, VariableDeclarationStackLayer::Bound(bound) => { if let Some(variable_declaration) = bound.variable_declarations.iter() .find(|x| x.name == variable_name) { return std::rc::Rc::clone(&variable_declaration); } bound.parent.find_or_create(variable_name) }, } } #[cfg(test)] pub fn free_variable_declarations_do(&self, f: F) -> G where F: Fn(&crate::VariableDeclarations) -> G { match self { VariableDeclarationStackLayer::Free(free) => f(&free.variable_declarations.borrow()), VariableDeclarationStackLayer::Bound(bound) => bound.parent.free_variable_declarations_do(f), } } }