tin 0.3.0

tin: a statically structurally typed embeddable programming language
Documentation
use std::collections;
use std::fmt;

use specs::Component;
use specs::VecStorage;

#[derive(Component, Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
#[storage(VecStorage)]
pub enum Type {
    Number(Number),
    String,
    Symbol(Symbol),
    Tuple(Tuple),
    Union(Union),
    Record(Record),
    Function(Function),
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub enum ScalarClass {
    Symbol,
    Integral(IntegralScalarClass),
    Fractional,
    Complex,
    Undefined,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub enum IntegralScalarClass {
    Unsigned,
    Signed,
    Any,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub enum Number {
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, VisitEntities, VisitEntitiesMut)]
pub struct Symbol {
    pub label: String,
}

#[derive(Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub struct Tuple {
    pub fields: Vec<Type>,
}

#[derive(Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub struct Union {
    pub alternatives: Vec<Symbol>,
}

#[derive(Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub struct Record {
    pub fields: collections::HashMap<String, Type>,
}

#[derive(Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub struct Function {
    pub parameters: Vec<Type>,
    pub result: Box<Type>,
}

#[derive(Component, Clone, Debug, Eq, Fail, PartialEq, VisitEntities, VisitEntitiesMut)]
#[storage(VecStorage)]
pub struct TypeError<E>
where
    E: fmt::Debug + Send + Sync + 'static,
{
    pub expected: ExpectedType,
    pub actual: Type,
    pub main_entity: E,
    pub aux_entities: Vec<AuxEntity<E>>,
}

#[derive(Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub struct AuxEntity<E> {
    pub entity: E,
    pub label: String,
}

#[derive(Clone, Debug, Eq, PartialEq, VisitEntities, VisitEntitiesMut)]
pub enum ExpectedType {
    Specific(Type),
    ScalarClass(ScalarClass),
    AnyOf(Vec<ExpectedType>),
    Union,
}

impl Type {
    pub fn scalar_class(&self) -> ScalarClass {
        match *self {
            Type::Number(ref n) => n.scalar_class(),
            Type::String => ScalarClass::Complex,
            Type::Symbol(_) => ScalarClass::Symbol,
            Type::Union(_) => ScalarClass::Undefined,
            Type::Tuple(_) => ScalarClass::Complex,
            Type::Record(_) => ScalarClass::Complex,
            Type::Function(_) => ScalarClass::Undefined,
        }
    }
}

impl Number {
    pub fn scalar_class(&self) -> ScalarClass {
        match *self {
            Number::U8 => ScalarClass::Integral(IntegralScalarClass::Unsigned),
            Number::U16 => ScalarClass::Integral(IntegralScalarClass::Unsigned),
            Number::U32 => ScalarClass::Integral(IntegralScalarClass::Unsigned),
            Number::U64 => ScalarClass::Integral(IntegralScalarClass::Unsigned),
            Number::I8 => ScalarClass::Integral(IntegralScalarClass::Signed),
            Number::I16 => ScalarClass::Integral(IntegralScalarClass::Signed),
            Number::I32 => ScalarClass::Integral(IntegralScalarClass::Signed),
            Number::I64 => ScalarClass::Integral(IntegralScalarClass::Signed),
            Number::F32 => ScalarClass::Fractional,
            Number::F64 => ScalarClass::Fractional,
        }
    }
}

impl Union {
    pub fn with(mut self, symbol: &Symbol) -> Union {
        match self.alternatives.binary_search(symbol) {
            Ok(_) => {}
            Err(n) => self.alternatives.insert(n, symbol.clone()),
        }

        self
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Type::Number(ref number) => number.fmt(f),
            Type::String => write!(f, "str"),
            Type::Symbol(ref label) => label.fmt(f),
            Type::Tuple(ref tuple) => tuple.fmt(f),
            Type::Union(ref union) => union.fmt(f),
            Type::Record(ref record) => record.fmt(f),
            Type::Function(ref function) => function.fmt(f),
        }
    }
}

impl fmt::Display for Number {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Number::U8 => write!(f, "u8"),
            Number::U16 => write!(f, "u16"),
            Number::U32 => write!(f, "u32"),
            Number::U64 => write!(f, "u64"),
            Number::I8 => write!(f, "i8"),
            Number::I16 => write!(f, "i16"),
            Number::I32 => write!(f, "i32"),
            Number::I64 => write!(f, "i64"),
            Number::F32 => write!(f, "f32"),
            Number::F64 => write!(f, "f64"),
        }
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, ":{}", self.label)
    }
}

impl fmt::Display for Tuple {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(")?;
        let mut needs_sep = false;
        for ty in &self.fields {
            if needs_sep {
                write!(f, ",")?;
            }
            ty.fmt(f)?;
            needs_sep = true;
        }
        write!(f, ")")?;
        Ok(())
    }
}

impl fmt::Display for Union {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut needs_sep = false;
        for ty in &self.alternatives {
            if needs_sep {
                write!(f, "|")?;
            }
            ty.fmt(f)?;
            needs_sep = true;
        }
        Ok(())
    }
}

impl fmt::Display for Record {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{{")?;
        let mut needs_sep = false;
        for (id, ty) in &self.fields {
            if needs_sep {
                write!(f, ",")?;
            }
            write!(f, "{}: ", id)?;
            ty.fmt(f)?;
            needs_sep = true;
        }
        write!(f, "}}")?;
        Ok(())
    }
}

impl fmt::Display for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "|")?;
        let mut needs_sep = false;
        for ty in &self.parameters {
            if needs_sep {
                write!(f, ",")?;
            }
            ty.fmt(f)?;
            needs_sep = true;
        }
        write!(f, "|")?;
        self.result.fmt(f)?;
        Ok(())
    }
}

impl<E> fmt::Display for TypeError<E>
where
    E: fmt::Debug + Send + Sync,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "expected ")?;
        self.expected.fmt(f)?;
        write!(f, " but got ")?;
        self.actual.fmt(f)?;
        Ok(())
    }
}

impl fmt::Display for ExpectedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExpectedType::Specific(ref ty) => ty.fmt(f),
            ExpectedType::ScalarClass(ref class) => class.fmt(f),
            ExpectedType::AnyOf(ref options) => {
                let last = options.len() - 1;
                for (i, option) in options.iter().enumerate() {
                    if i == last {
                        write!(f, " or ")?;
                    } else if i > 0 {
                        write!(f, ", ")?;
                    }
                    option.fmt(f)?;
                }
                Ok(())
            }
            ExpectedType::Union => f.write_str("any union type"),
        }
    }
}

impl fmt::Display for ScalarClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ScalarClass::Symbol => f.write_str("any symbol"),
            ScalarClass::Integral(IntegralScalarClass::Unsigned) => {
                f.write_str("any unsigned integer type")
            }
            ScalarClass::Integral(IntegralScalarClass::Signed) => {
                f.write_str("any signed integer type")
            }
            ScalarClass::Integral(IntegralScalarClass::Any) => f.write_str("any integer type"),
            ScalarClass::Fractional => f.write_str("any floating point type"),
            ScalarClass::Complex => f.write_str("any complex type"),
            ScalarClass::Undefined => f.write_str("any non-scalar type"),
        }
    }
}