mod convertible;
mod infer_check;
mod reduce;
mod sterm;
mod subst;
mod tests;
use crate::share::{Intro, Pattern, Rule, TopPattern};
use sterm::{LTerm, STerm};
pub type GCtx<'s> = crate::GCtx<crate::Symbol<'s>, Pattern<'s>, LTerm<'s>>;
pub type Typing<'s> = crate::Typing<LTerm<'s>, Option<LTerm<'s>>>;
pub type Check<'s> = crate::Typing<LTerm<'s>>;
type Result<T> = core::result::Result<T, Error>;
type IntroResult<'s> = Result<(Typing<'s>, Option<Check<'s>>)>;
#[derive(Debug)]
pub enum Error {
ProductExpected,
SortExpected,
BindNoType,
Unconvertible,
KindNotTypable,
UnexpectedKind,
DomainFreeAbstraction,
TypeAndTermEmpty,
TypeNotFound,
}
impl From<sterm::UnexpectedKind> for Error {
fn from(_: sterm::UnexpectedKind) -> Self {
Error::UnexpectedKind
}
}
fn declare<'s>(ty: LTerm<'s>, gc: &GCtx<'s>) -> IntroResult<'s> {
let ty_of_ty = STerm::from(&ty).infer(gc, &mut Default::default())?;
if !matches!(ty_of_ty, STerm::Kind | STerm::Type) {
return Err(Error::SortExpected);
}
Ok((Typing::new(ty, None), None))
}
fn define<'s>(ty: Option<LTerm<'s>>, tm: LTerm<'s>, gc: &GCtx<'s>) -> IntroResult<'s> {
let check = ty.is_some();
let ty = if let Some(ty) = ty {
let _ = STerm::from(&ty).infer(gc, &mut Default::default())?;
ty
} else {
LTerm::try_from(&STerm::from(&tm).infer(gc, &mut Default::default())?)?
};
let check = check.then(|| Check::new(ty.clone(), tm.clone()));
Ok((Typing::new(ty, Some(tm)), check))
}
fn theorem<'s>(ty: LTerm<'s>, tm: LTerm<'s>, gc: &GCtx<'s>) -> IntroResult<'s> {
let _ = STerm::from(&ty).infer(gc, &mut Default::default())?;
Ok((Typing::new(ty.clone(), None), Some(Check::new(ty, tm))))
}
pub fn intro<'s>(it: Intro<'s>, gc: &GCtx<'s>) -> IntroResult<'s> {
match it {
Intro::Declaration(ty) => declare(ty, gc),
Intro::Definition(oty, otm) => match (oty, otm) {
(Some(ty), None) => declare(ty, gc),
(oty, Some(tm)) => define(oty, tm, gc),
(None, None) => Err(Error::TypeAndTermEmpty),
},
Intro::Theorem(ty, tm) => theorem(ty, tm, gc),
}
}
pub fn rewrite<'s>(rule: crate::Rule<LTerm<'s>>, gc: &GCtx<'s>) -> Result<Check<'s>> {
let mut lc = rule.ctx.iter().map(STerm::from).collect();
Ok(Check {
tm: rule.rhs,
ty: LTerm::try_from(&STerm::from(&rule.lhs).infer(gc, &mut lc)?)?,
lc: rule.ctx.clone(),
})
}
impl<'s> Check<'s> {
pub fn check(self, gc: &GCtx<'s>) -> Result<()> {
let mut lc = self.lc.iter().map(STerm::from).collect();
let tm = STerm::from(&self.tm);
let ty = STerm::from(&self.ty);
if tm.check(gc, &mut lc, ty)? {
Ok(())
} else {
Err(Error::Unconvertible)
}
}
}