lyte 0.1.0

Rust-like typesystem created for the Lumina project
Documentation
use super::*;
use itertools::Itertools;
use std::fmt;

#[derive(Debug, Clone)]
pub struct Sum<D: TypeData> {
    pub identifier: D::Concrete,
    pub variants: Vec<TypesBuf<D>>,
}

impl<D: TypeData> Sum<D> {
    pub fn new(identifier: D::Concrete, variants: Vec<TypesBuf<D>>) -> Self {
        Self { identifier, variants }
    }

    pub fn to_foreign(self, generics: Generics<D>) -> ForeignSum<D> {
        ForeignSum { generics, sum: self }
    }
}

#[derive(Debug, Clone)]
pub struct ForeignSum<D: TypeData> {
    pub generics: Generics<D>,
    pub sum: Sum<D>,
}

pub struct InstantiatedSum<'a, D: TypeData> {
    mapping: Mapping<D>,
    pub sum: &'a Sum<D>,
}

impl<D: TypeData> ForeignSum<D> {
    pub fn instantiate<'s>(&'s self, tenv: &mut TEnv<D>) -> InstantiatedSum<'s, D> {
        let mapping = self.generics.to_mapping(tenv);
        InstantiatedSum { mapping, sum: &self.sum }
    }
}

impl<'a, D: TypeData> InstantiatedSum<'a, D> {
    pub fn variant(&self, variant: usize) -> TypesBuf<D> {
        let variant = self
            .sum
            .variants
            .get(variant)
            .expect("variant does not exist");

        self.mapping.apply_types(variant)
    }

    pub fn constructor(&self, ret_meta: D::Meta, variant: usize) -> Function<D> {
        let params = self.variant(variant);
        let returns = self.to_type(ret_meta);

        Function::new(params, returns)
    }

    pub fn mapping_mut(&mut self) -> &mut Mapping<D> {
        &mut self.mapping
    }
}

impl_to_type!(InstantiatedSum<'a, D>, sum);

impl<D: TypeData> fmt::Display for ForeignSum<D> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.generics.is_empty() {
            self.sum.fmt(f)
        } else {
            write!(f, "{}. {}", &self.generics, &self.sum)
        }
    }
}

impl<D: TypeData> fmt::Display for Sum<D> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} = {}",
            self.identifier,
            self.variants
                .iter()
                .format_with(" | ", |params, f| f(&format_args!(
                    "_ {}",
                    params.iter().format(" ")
                )))
        )
    }
}