use std::{cell::RefCell, collections::HashMap, hash::Hash, rc::Rc}; use super::{ ast::Tree, typed::{GroundType, Type}, }; #[derive(Debug)] pub struct Intern(Rc); impl PartialEq for Intern { fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.0, &other.0) } } impl Eq for Intern {} impl Hash for Intern { fn hash(&self, state: &mut H) { Rc::as_ptr(&self.0).hash(state) } } impl From> for Intern { fn from(inner: Rc) -> Self { Self(inner) } } #[derive(Debug)] pub struct TreeInterner { epsilon: Option>, bottom: Option>, identity: Option>, literal: HashMap>, cat: HashMap<(Intern, Intern), Rc>, alt: HashMap<(Intern, Intern), Rc>, fix: HashMap, Rc>, call: HashMap<(Intern, Intern), Rc>, } impl TreeInterner { pub fn epsilon(&mut self) -> Rc { self.epsilon .get_or_insert_with(|| Rc::new(Tree::Epsilon)) .clone() } pub fn bottom(&mut self) -> Rc { self.bottom .get_or_insert_with(|| Rc::new(Tree::Bottom)) .clone() } pub fn identity(&mut self) -> Rc { self.identity .get_or_insert_with(|| Rc::new(Tree::Identity)) .clone() } pub fn literal(&mut self, lit: String) -> Rc { self.literal .entry(lit) .or_insert_with_key(|lit| Rc::new(Tree::Literal(lit.clone()))) .clone() } pub fn cat(&mut self, front: Rc, back: Rc) -> Rc { self.cat .entry((Intern(front), Intern(back))) .or_insert_with_key(|(front, back)| Rc::new(Tree::Cat(front.0.clone(), back.0.clone()))) .clone() } pub fn alt(&mut self, left: Rc, right: Rc) -> Rc { self.alt .entry((Intern(left), Intern(right))) .or_insert_with_key(|(left, right)| Rc::new(Tree::Alt(left.0.clone(), right.0.clone()))) .clone() } pub fn fix(&mut self, inner: Rc) -> Rc { self.fix .entry(Intern(inner)) .or_insert_with_key(|inner| Rc::new(Tree::Fix(inner.0.clone()))) .clone() } pub fn call(&mut self, fun: Rc, arg: Rc) -> Rc { self.call .entry((Intern(fun), Intern(arg))) .or_insert_with_key(|(fun, arg)| Rc::new(Tree::Call(fun.0.clone(), arg.0.clone()))) .clone() } } #[derive(Debug)] pub struct TypeInterner { epsilon: Option>, bottom: Option>, character: HashMap>, cat: HashMap<(Intern, Intern), Rc>, alt: HashMap<(Intern, Intern), Rc>, fix: HashMap, Rc>, } impl TypeInterner { pub fn epsilon(&mut self) -> Rc { self.epsilon .get_or_insert_with(|| Rc::new(GroundType::Epsilon.into())) .clone() } pub fn bottom(&mut self) -> Rc { self.bottom .get_or_insert_with(|| Rc::new(GroundType::Bottom.into())) .clone() } pub fn character(&mut self, c: char) -> Rc { self.character .entry(c) .or_insert_with(|| Rc::new(GroundType::Character(c).into())) .clone() } pub fn cat(&mut self, front: Rc, back: Rc) -> Rc { self.cat .entry((Intern(front), Intern(back))) .or_insert_with_key(|(front, back)| { Rc::new( GroundType::Cat(RefCell::new(front.0.clone()), RefCell::new(back.0.clone())) .into(), ) }) .clone() } pub fn alt(&mut self, left: Rc, right: Rc) -> Rc { self.alt .entry((Intern(left), Intern(right))) .or_insert_with_key(|(left, right)| { Rc::new( GroundType::Alt(RefCell::new(left.0.clone()), RefCell::new(right.0.clone())) .into(), ) }) .clone() } }