diff options
Diffstat (limited to 'src/chomp/typed.rs')
-rw-r--r-- | src/chomp/typed.rs | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/chomp/typed.rs b/src/chomp/typed.rs new file mode 100644 index 0000000..50d8155 --- /dev/null +++ b/src/chomp/typed.rs @@ -0,0 +1,274 @@ +use std::{borrow::BorrowMut, cell::RefCell, rc::Rc}; + +use super::{ + ast::{Lambda, Tree}, + Context, +}; + +#[derive(Clone, Debug)] +pub enum Constraint {} + +#[derive(Clone, Debug)] +pub enum CatCheckError {} + +#[derive(Clone, Debug)] +pub enum TypeError { + NeedGroundType(Rc<Type>), + CatCheck(CatCheckError), +} + +#[derive(Debug)] +pub struct AlgebraicType {} + +#[derive(Debug)] +pub enum GroundType { + Epsilon, + Bottom, + Character(char), + Variable, + Cat(RefCell<Rc<GroundType>>, RefCell<Rc<GroundType>>), + Alt(RefCell<Rc<GroundType>>, RefCell<Rc<GroundType>>), + Fix(RefCell<Rc<GroundType>>, RefCell<Rc<GroundType>>), +} + +#[derive(Clone, Debug)] +pub struct UnificationError(pub Rc<Type>, pub Rc<Type>); + +impl GroundType { + pub fn is_variable(&self) -> bool { + matches!(self, Self::Variable) + } + + pub fn substitute(self: &mut Rc<Self>, from: &Rc<Self>, into: &Rc<Self>) { + if Rc::ptr_eq(self, from) { + *self = into.clone(); + return; + } + + match self.as_ref() { + GroundType::Epsilon => {} + GroundType::Bottom => {} + GroundType::Character(_) => {} + GroundType::Variable => {} + GroundType::Cat(front, back) => { + front.borrow_mut().substitute(from, into); + back.borrow_mut().substitute(from, into); + } + GroundType::Alt(left, right) => { + left.borrow_mut().substitute(from, into); + right.borrow_mut().substitute(from, into); + } + GroundType::Fix(_, inner) => { + inner.borrow_mut().substitute(from, into); + } + } + } + + pub fn occurs_in(self: &Rc<Self>, other: &Rc<Self>) -> bool { + if Rc::ptr_eq(self, other) { + return true; + } + + match other.as_ref() { + GroundType::Epsilon => false, + GroundType::Bottom => false, + GroundType::Character(_) => false, + GroundType::Variable => false, + GroundType::Cat(front, back) => { + self.occurs_in(&front.borrow()) || self.occurs_in(&back.borrow()) + } + GroundType::Alt(left, right) => { + self.occurs_in(&left.borrow()) || self.occurs_in(&right.borrow()) + } + GroundType::Fix(arg, out) => { + self.occurs_in(&arg.borrow()) || self.occurs_in(&out.borrow()) + } + } + } + + pub fn unify<'a>( + self: &'a mut Rc<Self>, + other: &'a mut Rc<Self>, + ) -> Result<(), UnificationError> { + if Rc::ptr_eq(self, other) { + return Ok(()); + } + + match (self.as_ref(), other.as_ref()) { + (GroundType::Epsilon, GroundType::Epsilon) => Ok(()), + (GroundType::Bottom, GroundType::Bottom) => Ok(()), + (GroundType::Character(c), GroundType::Character(d)) if c == d => Ok(()), + (GroundType::Cat(front1, back1), GroundType::Cat(front2, back2)) => { + front1.borrow_mut().unify(&mut front2.borrow_mut())?; + back1.borrow_mut().unify(&mut back2.borrow_mut()) + } + (GroundType::Alt(left1, right1), GroundType::Alt(left2, right2)) => { + left1.borrow_mut().unify(&mut left2.borrow_mut())?; + right1.borrow_mut().unify(&mut right2.borrow_mut()) + } + (GroundType::Fix(arg1, out1), GroundType::Fix(arg2, out2)) => { + let new_arg = Rc::new(GroundType::Variable); + out1.borrow_mut().substitute(&arg1.borrow(), &new_arg); + out2.borrow_mut().substitute(&arg2.borrow(), &new_arg); + arg1.replace(new_arg.clone()); + arg2.replace(new_arg.clone()); + out1.borrow_mut().unify(&mut out2.borrow_mut()) + } + (GroundType::Variable, GroundType::Variable) => { + self = other; + Ok(()) + } + (GroundType::Variable, _) if !self.occurs_in(other) => { + self = other; + Ok(()) + } + (_, GroundType::Variable) if !other.occurs_in(self) => { + other = self; + Ok(()) + } + _ => Err(UnificationError( + Rc::new(self.clone().into()), + Rc::new(other.clone().into()), + )), + } + } +} + +/// Function type where the formal parameter is guarded in the body. +/// The actual parameter is checked in an unguarded context. +#[derive(Debug)] +pub struct GuardedFunction(pub RefCell<Rc<GroundType>>, pub RefCell<Rc<Type>>); + +#[derive(Debug)] +pub enum Type { + Ground(RefCell<Rc<GroundType>>), + /// Function type where the formal parameter is unguarded in the body. + /// The actual parameter is checked in a guarded context. + UnguardedFunction(RefCell<Rc<GroundType>>, RefCell<Rc<Type>>), + GuardedFunction(GuardedFunction), + Variable, +} + +impl Type { + pub fn try_as_ground<'a>( + self: &'a Rc<Self>, + ) -> Result<&'a RefCell<Rc<GroundType>>, &'a Rc<Self>> { + if let Type::Ground(g) = self.as_ref() { + Ok(g) + } else { + Err(self) + } + } + pub fn unify<'a>( + self: &'a mut Rc<Self>, + other: &'a mut Rc<Self>, + ) -> Result<(), UnificationError> { + if Rc::ptr_eq(self, other) { + return Ok(()); + } + + match self.as_ref() { + Type::Ground(g) => { + if let Type::Ground(o) = other.as_ref() { + g.borrow_mut().unify(&mut o.borrow_mut()) + } else { + Err(UnificationError(self.clone(), other.clone())) + } + } + Type::UnguardedFunction(arg, out) => { + if let Type::UnguardedFunction(o_arg, o_out) = other.as_ref() { + arg.borrow_mut().unify(&mut o_arg.borrow_mut())?; + out.borrow_mut().unify(&mut o_out.borrow_mut()) + } else { + Err(UnificationError(self.clone(), other.clone())) + } + } + Type::GuardedFunction(GuardedFunction(arg, out)) => { + if let Type::GuardedFunction(GuardedFunction(o_arg, o_out)) = other.as_ref() { + arg.borrow_mut().unify(&mut o_arg.borrow_mut())?; + out.borrow_mut().unify(&mut o_out.borrow_mut()) + } else { + Err(UnificationError(self.clone(), other.clone())) + } + } + Type::Variable => { + self = other; + Ok(()) + } + } + } +} + +impl From<GroundType> for Type { + fn from(ty: GroundType) -> Self { + Rc::new(ty).into() + } +} + +impl From<Rc<GroundType>> for Type { + fn from(ty: Rc<GroundType>) -> Self { + Self::Ground(RefCell::new(ty)) + } +} + +pub fn type_of(ctx: &mut Context, tree: &Rc<Tree>) -> Result<Rc<Type>, TypeError> { + match tree.as_ref() { + Tree::Epsilon => Ok(ctx.type_interner.epsilon()), + Tree::Bottom => Ok(ctx.type_interner.bottom()), + Tree::Identity => { + let arg = Rc::new(GroundType::Variable); + Ok(Rc::new(Type::UnguardedFunction( + RefCell::new(arg), + RefCell::new(Rc::new(arg.into())), + ))) + } + Tree::Literal(l) => { + if let Some(c) = l.chars().next() { + Ok(ctx.type_interner.character(c)) + } else { + Ok(ctx.type_interner.epsilon()) + } + } + Tree::Variable => todo!(), // ctx.lookup_type_variable(tree), + Tree::Cat(front, back) => { + let mut front_ty: Rc<Type> = Rc::new(GroundType::Variable.into()); + let mut back_ty: Rc<Type> = Rc::new(GroundType::Variable.into()); + ctx.type_of(front)? + .unify(&mut front_ty) + .map_err(|_| todo!())?; + ctx.type_of(back)? + .unify(&mut back_ty) + .map_err(|_| todo!())?; + let front_ty = front_ty.try_as_ground().unwrap(); + let back_ty = back_ty.try_as_ground().unwrap(); + Ok(ctx + .type_interner + .cat(front_ty.borrow().clone(), back_ty.borrow().clone())) + } + Tree::Alt(left, right) => { + let mut left_ty: Rc<Type> = Rc::new(GroundType::Variable.into()); + let mut right_ty: Rc<Type> = Rc::new(GroundType::Variable.into()); + ctx.type_of(left)? + .unify(&mut left_ty) + .map_err(|_| todo!())?; + ctx.type_of(right)? + .unify(&mut right_ty) + .map_err(|_| todo!())?; + let left_ty = left_ty.try_as_ground().unwrap(); + let right_ty = right_ty.try_as_ground().unwrap(); + Ok(ctx + .type_interner + .alt(left_ty.borrow().clone(), right_ty.borrow().clone())) + } + Tree::Fix(inner) => { + let shape = Rc::new(Type::GuardedFunction(GuardedFunction(RefCell::new(Rc::new(GroundType::Variable)), RefCell::new(Rc::new(GroundType::Variable.into()))))); + ctx.type_of(inner)? + .unify(&mut shape) + .map_err(|_| todo!())?; + todo!() + } + Tree::Call(_, _) => todo!(), + Tree::Lambda(_) => todo!(), + Tree::Let(_, _, _) => todo!(), + } +} |