use voile_util::uid::{next_uid, UID};
use crate::syntax::common::ConHead;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Pat<Ix, Term> {
Var(Ix),
Refl,
Absurd,
Cons(bool, ConHead, Vec<Self>),
Forced(Term),
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Copat<Ix, Term> {
App(Pat<Ix, Term>),
Proj(String),
}
pub trait PatCommon {
fn is_split(&self) -> bool;
fn is_solved(&self) -> bool {
!self.is_split()
}
}
impl<Ix, Term> PatCommon for Pat<Ix, Term> {
fn is_split(&self) -> bool {
use Pat::*;
match self {
Refl | Cons(..) => true,
Var(..) | Absurd | Forced(..) => false,
}
}
}
impl<Ix, Term> PatCommon for Copat<Ix, Term> {
fn is_split(&self) -> bool {
match self {
Copat::App(p) => p.is_split(),
Copat::Proj(..) => false,
}
}
}
impl<Ix, Term> Copat<Ix, Term> {
pub fn absurd() -> Self {
Copat::App(Pat::Absurd)
}
pub fn reflexivity() -> Self {
Copat::App(Pat::Refl)
}
pub fn var(ix: Ix) -> Self {
Copat::App(Pat::Var(ix))
}
pub fn term(term: Term) -> Self {
Copat::App(Pat::Forced(term))
}
pub fn cons(is_forced: bool, cons: ConHead, pats: Vec<Pat<Ix, Term>>) -> Self {
Copat::App(Pat::Cons(is_forced, cons, pats))
}
pub fn is_proj(&self) -> bool {
match self {
Copat::App(_) => false,
Copat::Proj(_) => true,
}
}
pub fn map_app<Ix2, Term2>(
self,
f: impl FnOnce(Pat<Ix, Term>) -> Pat<Ix2, Term2>,
) -> Copat<Ix2, Term2> {
match self {
Copat::App(app) => Copat::App(f(app)),
Copat::Proj(field) => Copat::Proj(field),
}
}
}
impl<Term> Copat<UID, Term> {
pub fn fresh_var() -> Self {
Self::var(unsafe { next_uid() })
}
}