#[cfg(doc)]
use crate::traverse::TraverseAlloc;
use crate::{
error::{ParseError, ParseErrors},
identifier::{Ident, LocIdent},
};
use std::{collections::HashSet, convert::Infallible};
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct RecordRowF<Ty> {
pub id: LocIdent,
pub typ: Ty,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct EnumRowF<Ty> {
pub id: LocIdent,
pub typ: Option<Ty>,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum RecordRowsF<Ty, RRows> {
Empty,
Extend { row: RecordRowF<Ty>, tail: RRows },
TailVar(LocIdent),
TailDyn,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum EnumRowsF<Ty, ERows> {
Empty,
Extend { row: EnumRowF<Ty>, tail: ERows },
TailVar(LocIdent),
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub enum VarKind {
#[default]
Type,
EnumRows { excluded: HashSet<Ident> },
RecordRows { excluded: HashSet<Ident> },
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum VarKindDiscriminant {
Type,
EnumRows,
RecordRows,
}
impl From<&VarKind> for VarKindDiscriminant {
fn from(vk: &VarKind) -> Self {
match vk {
VarKind::Type => VarKindDiscriminant::Type,
VarKind::EnumRows { .. } => VarKindDiscriminant::EnumRows,
VarKind::RecordRows { .. } => VarKindDiscriminant::RecordRows,
}
}
}
#[derive(Clone, Debug, Copy, Eq, PartialEq)]
pub enum DictTypeFlavour {
Type,
Contract,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TypeF<Ty, RRows, ERows, Te> {
Dyn,
Number,
Bool,
String,
Symbol,
ForeignId,
Contract(Te),
Arrow(Ty, Ty),
Var(Ident),
Forall {
var: LocIdent,
var_kind: VarKind,
body: Ty,
},
Enum(ERows),
Record(RRows),
Dict {
type_fields: Ty,
flavour: DictTypeFlavour,
},
Array(Ty),
Wildcard(usize),
}
impl<Ty, RRows> RecordRowsF<Ty, RRows> {
pub fn try_map_state<TyO, RRowsO, FTy, FRRows, S, E>(
self,
mut f_ty: FTy,
mut f_rrows: FRRows,
state: &mut S,
) -> Result<RecordRowsF<TyO, RRowsO>, E>
where
FTy: FnMut(Ty, &mut S) -> Result<TyO, E>,
FRRows: FnMut(RRows, &mut S) -> Result<RRowsO, E>,
{
match self {
RecordRowsF::Empty => Ok(RecordRowsF::Empty),
RecordRowsF::Extend {
row: RecordRowF { id, typ },
tail,
} => Ok(RecordRowsF::Extend {
row: RecordRowF {
id,
typ: f_ty(typ, state)?,
},
tail: f_rrows(tail, state)?,
}),
RecordRowsF::TailDyn => Ok(RecordRowsF::TailDyn),
RecordRowsF::TailVar(id) => Ok(RecordRowsF::TailVar(id)),
}
}
pub fn try_map<TyO, RRowsO, FTy, FRRows, E>(
self,
mut f_ty: FTy,
mut f_rrows: FRRows,
) -> Result<RecordRowsF<TyO, RRowsO>, E>
where
FTy: FnMut(Ty) -> Result<TyO, E>,
FRRows: FnMut(RRows) -> Result<RRowsO, E>,
{
let f_ty_lifted = |rrow: Ty, _: &mut ()| -> Result<TyO, E> { f_ty(rrow) };
let f_rrows_lifted = |rrows: RRows, _: &mut ()| -> Result<RRowsO, E> { f_rrows(rrows) };
self.try_map_state(f_ty_lifted, f_rrows_lifted, &mut ())
}
pub fn map_state<TyO, RRowsO, FTy, FRRows, S>(
self,
mut f_ty: FTy,
mut f_rrows: FRRows,
state: &mut S,
) -> RecordRowsF<TyO, RRowsO>
where
FTy: FnMut(Ty, &mut S) -> TyO,
FRRows: FnMut(RRows, &mut S) -> RRowsO,
{
let f_ty_lifted = |rrow: Ty, state: &mut S| -> Result<TyO, ()> { Ok(f_ty(rrow, state)) };
let f_rrows_lifted =
|rrows: RRows, state: &mut S| -> Result<RRowsO, ()> { Ok(f_rrows(rrows, state)) };
self.try_map_state(f_ty_lifted, f_rrows_lifted, state)
.unwrap()
}
pub fn map<TyO, RRowsO, FTy, FRRows>(
self,
mut f_ty: FTy,
mut f_rrows: FRRows,
) -> RecordRowsF<TyO, RRowsO>
where
FTy: FnMut(Ty) -> TyO,
FRRows: FnMut(RRows) -> RRowsO,
{
let f_ty_lifted = |rrow: Ty| -> Result<TyO, Infallible> { Ok(f_ty(rrow)) };
let f_rrows_lifted = |rrows: RRows| -> Result<RRowsO, Infallible> { Ok(f_rrows(rrows)) };
self.try_map(f_ty_lifted, f_rrows_lifted).unwrap()
}
}
impl<Ty, ERows> EnumRowsF<Ty, ERows> {
pub fn try_map_state<TyO, ERowsO, FTy, FERows, S, E>(
self,
mut f_ty: FTy,
f_erows: FERows,
state: &mut S,
) -> Result<EnumRowsF<TyO, ERowsO>, E>
where
FTy: FnMut(Ty, &mut S) -> Result<TyO, E>,
FERows: FnOnce(ERows, &mut S) -> Result<ERowsO, E>,
{
match self {
EnumRowsF::Empty => Ok(EnumRowsF::Empty),
EnumRowsF::Extend {
row: EnumRowF { id, typ },
tail,
} => Ok(EnumRowsF::Extend {
row: EnumRowF {
id,
typ: typ.map(|ty| f_ty(ty, state)).transpose()?,
},
tail: f_erows(tail, state)?,
}),
EnumRowsF::TailVar(id) => Ok(EnumRowsF::TailVar(id)),
}
}
pub fn try_map<TyO, ERowsO, FTy, FERows, E>(
self,
mut f_ty: FTy,
mut f_erows: FERows,
) -> Result<EnumRowsF<TyO, ERowsO>, E>
where
FTy: FnMut(Ty) -> Result<TyO, E>,
FERows: FnMut(ERows) -> Result<ERowsO, E>,
{
let f_ty_lifted = |erow: Ty, _: &mut ()| -> Result<TyO, E> { f_ty(erow) };
let f_erows_lifted = |erows: ERows, _: &mut ()| -> Result<ERowsO, E> { f_erows(erows) };
self.try_map_state(f_ty_lifted, f_erows_lifted, &mut ())
}
pub fn map_state<TyO, ERowsO, FTy, FERows, S>(
self,
mut f_ty: FTy,
mut f_erows: FERows,
state: &mut S,
) -> EnumRowsF<TyO, ERowsO>
where
FTy: FnMut(Ty, &mut S) -> TyO,
FERows: FnMut(ERows, &mut S) -> ERowsO,
{
let f_ty_lifted = |erow: Ty, state: &mut S| -> Result<TyO, ()> { Ok(f_ty(erow, state)) };
let f_erows_lifted =
|erows: ERows, state: &mut S| -> Result<ERowsO, ()> { Ok(f_erows(erows, state)) };
self.try_map_state(f_ty_lifted, f_erows_lifted, state)
.unwrap()
}
pub fn map<TyO, ERowsO, FTy, FERows>(
self,
mut f_ty: FTy,
mut f_erows: FERows,
) -> EnumRowsF<TyO, ERowsO>
where
FTy: FnMut(Ty) -> TyO,
FERows: FnMut(ERows) -> ERowsO,
{
let f_ty_lifted = |erow: Ty| -> Result<TyO, Infallible> { Ok(f_ty(erow)) };
let f_erows_lifted = |erows: ERows| -> Result<ERowsO, Infallible> { Ok(f_erows(erows)) };
self.try_map(f_ty_lifted, f_erows_lifted).unwrap()
}
}
impl<Ty, RRows, ERows, Te> TypeF<Ty, RRows, ERows, Te> {
pub fn try_map_state<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe, S, E>(
self,
mut f: FTy,
mut f_rrows: FRRows,
mut f_erows: FERows,
mut f_ctr: FTe,
state: &mut S,
) -> Result<TypeF<TyO, RRowsO, ERowsO, TeO>, E>
where
FTy: FnMut(Ty, &mut S) -> Result<TyO, E>,
FRRows: FnMut(RRows, &mut S) -> Result<RRowsO, E>,
FERows: FnMut(ERows, &mut S) -> Result<ERowsO, E>,
FTe: FnMut(Te, &mut S) -> Result<TeO, E>,
{
match self {
TypeF::Dyn => Ok(TypeF::Dyn),
TypeF::Number => Ok(TypeF::Number),
TypeF::Bool => Ok(TypeF::Bool),
TypeF::String => Ok(TypeF::String),
TypeF::ForeignId => Ok(TypeF::ForeignId),
TypeF::Symbol => Ok(TypeF::Symbol),
TypeF::Contract(t) => Ok(TypeF::Contract(f_ctr(t, state)?)),
TypeF::Arrow(dom, codom) => Ok(TypeF::Arrow(f(dom, state)?, f(codom, state)?)),
TypeF::Var(i) => Ok(TypeF::Var(i)),
TypeF::Forall {
var,
var_kind,
body,
} => Ok(TypeF::Forall {
var,
var_kind,
body: f(body, state)?,
}),
TypeF::Enum(erows) => Ok(TypeF::Enum(f_erows(erows, state)?)),
TypeF::Record(rrows) => Ok(TypeF::Record(f_rrows(rrows, state)?)),
TypeF::Dict {
type_fields,
flavour: attrs,
} => Ok(TypeF::Dict {
type_fields: f(type_fields, state)?,
flavour: attrs,
}),
TypeF::Array(t) => Ok(TypeF::Array(f(t, state)?)),
TypeF::Wildcard(i) => Ok(TypeF::Wildcard(i)),
}
}
pub fn try_map<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe, E>(
self,
mut f: FTy,
mut f_rrows: FRRows,
mut f_erows: FERows,
mut f_ctr: FTe,
) -> Result<TypeF<TyO, RRowsO, ERowsO, TeO>, E>
where
FTy: FnMut(Ty) -> Result<TyO, E>,
FRRows: FnMut(RRows) -> Result<RRowsO, E>,
FERows: FnMut(ERows) -> Result<ERowsO, E>,
FTe: FnMut(Te) -> Result<TeO, E>,
{
let f_lifted = |ty: Ty, _: &mut ()| -> Result<TyO, E> { f(ty) };
let f_rrows_lifted = |rrows: RRows, _: &mut ()| -> Result<RRowsO, E> { f_rrows(rrows) };
let f_erows_lifted = |erows: ERows, _: &mut ()| -> Result<ERowsO, E> { f_erows(erows) };
let f_ctr_lifted = |ctr: Te, _: &mut ()| -> Result<TeO, E> { f_ctr(ctr) };
self.try_map_state(
f_lifted,
f_rrows_lifted,
f_erows_lifted,
f_ctr_lifted,
&mut (),
)
}
pub fn map_state<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe, S>(
self,
mut f: FTy,
mut f_rrows: FRRows,
mut f_erows: FERows,
mut f_ctr: FTe,
state: &mut S,
) -> TypeF<TyO, RRowsO, ERowsO, TeO>
where
FTy: FnMut(Ty, &mut S) -> TyO,
FRRows: FnMut(RRows, &mut S) -> RRowsO,
FERows: FnMut(ERows, &mut S) -> ERowsO,
FTe: FnMut(Te, &mut S) -> TeO,
{
let f_lifted = |ty: Ty, state: &mut S| -> Result<TyO, Infallible> { Ok(f(ty, state)) };
let f_rrows_lifted = |rrows: RRows, state: &mut S| -> Result<RRowsO, Infallible> {
Ok(f_rrows(rrows, state))
};
let f_erows_lifted = |erows: ERows, state: &mut S| -> Result<ERowsO, Infallible> {
Ok(f_erows(erows, state))
};
let f_ctr_lifted =
|ctr: Te, state: &mut S| -> Result<TeO, Infallible> { Ok(f_ctr(ctr, state)) };
self.try_map_state(
f_lifted,
f_rrows_lifted,
f_erows_lifted,
f_ctr_lifted,
state,
)
.unwrap()
}
pub fn map<TyO, RRowsO, ERowsO, TeO, FTy, FRRows, FERows, FTe>(
self,
mut f: FTy,
mut f_rrows: FRRows,
mut f_erows: FERows,
mut f_ctr: FTe,
) -> TypeF<TyO, RRowsO, ERowsO, TeO>
where
FTy: FnMut(Ty) -> TyO,
FRRows: FnMut(RRows) -> RRowsO,
FERows: FnMut(ERows) -> ERowsO,
FTe: FnMut(Te) -> TeO,
{
let f_lifted = |ty: Ty, _: &mut ()| -> TyO { f(ty) };
let f_rrows_lifted = |rrows: RRows, _: &mut ()| -> RRowsO { f_rrows(rrows) };
let f_erows_lifted = |erows: ERows, _: &mut ()| -> ERowsO { f_erows(erows) };
let f_ctr_lifted = |ctr: Te, _: &mut ()| -> TeO { f_ctr(ctr) };
self.map_state(
f_lifted,
f_rrows_lifted,
f_erows_lifted,
f_ctr_lifted,
&mut (),
)
}
pub fn is_wildcard(&self) -> bool {
matches!(self, TypeF::Wildcard(_))
}
pub fn is_contract(&self) -> bool {
matches!(self, TypeF::Contract(_))
}
}
#[derive(Clone, Debug)]
pub struct UnboundTypeVariableError(pub LocIdent);
impl From<UnboundTypeVariableError> for ParseError {
fn from(err: UnboundTypeVariableError) -> Self {
ParseError::UnboundTypeVariables(vec![err.0])
}
}
impl From<UnboundTypeVariableError> for ParseErrors {
fn from(err: UnboundTypeVariableError) -> Self {
ParseErrors::from(ParseError::from(err))
}
}