use crate::{handle::Handle, table::Table, type_kind::TypeKind};
use cl_ast::{PathPart, Ty, TyArray, TyFn, TyKind, TyRef, TySlice, TyTuple};
#[derive(Clone, Debug, PartialEq, Eq)] pub enum Error {
BadPath { parent: Handle, path: Vec<PathPart> },
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::BadPath { parent, path } => {
write!(f, "No item at path {parent}")?;
for part in path {
write!(f, "::{part}")?;
}
}
}
Ok(())
}
}
pub trait TypeExpression<Out = Handle> {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Out, Error>;
}
impl TypeExpression for Ty {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
self.kind.evaluate(table, node)
}
}
impl TypeExpression for TyKind {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
match self {
TyKind::Never => Ok(table.anon_type(TypeKind::Never)),
TyKind::Empty => Ok(table.anon_type(TypeKind::Empty)),
TyKind::Path(p) => p.evaluate(table, node),
TyKind::Array(a) => a.evaluate(table, node),
TyKind::Slice(s) => s.evaluate(table, node),
TyKind::Tuple(t) => t.evaluate(table, node),
TyKind::Ref(r) => r.evaluate(table, node),
TyKind::Fn(f) => f.evaluate(table, node),
}
}
}
impl TypeExpression for cl_ast::Path {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
let Self { absolute, parts } = self;
parts.evaluate(table, if *absolute { table.root() } else { node })
}
}
impl TypeExpression for [PathPart] {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
table
.nav(node, self)
.ok_or_else(|| Error::BadPath { parent: node, path: self.to_owned() })
}
}
impl TypeExpression for TyArray {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
let Self { ty, count } = self;
let kind = TypeKind::Array(ty.evaluate(table, node)?, *count);
Ok(table.anon_type(kind))
}
}
impl TypeExpression for TySlice {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
let Self { ty } = self;
let kind = TypeKind::Slice(ty.evaluate(table, node)?);
Ok(table.anon_type(kind))
}
}
impl TypeExpression for TyTuple {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
let Self { types } = self;
let kind = match types.len() {
0 => TypeKind::Empty,
_ => TypeKind::Tuple(types.evaluate(table, node)?),
};
Ok(table.anon_type(kind))
}
}
impl TypeExpression for TyRef {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
let Self { mutable: _, count, to } = self;
let mut t = to.evaluate(table, node)?;
for _ in 0..*count {
let kind = TypeKind::Ref(t);
t = table.anon_type(kind)
}
Ok(t)
}
}
impl TypeExpression for TyFn {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
let Self { args, rety } = self;
let kind = TypeKind::FnSig {
args: args.evaluate(table, node)?,
rety: match rety {
Some(ty) => ty.evaluate(table, node)?,
None => TyKind::Empty.evaluate(table, node)?,
},
};
Ok(table.anon_type(kind))
}
}
impl<T: TypeExpression<U>, U> TypeExpression<Vec<U>> for [T] {
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Vec<U>, Error> {
let mut out = Vec::with_capacity(self.len());
for te in self {
out.push(te.evaluate(table, node)?) }
Ok(out)
}
}