pub mod util; pub mod display; pub mod check; pub mod subst; use crate::sexp::SExp; #[derive(Clone,Debug,PartialEq)] pub enum Type { Integer, Boolean, Arrow(Box, Box), List(Vec), /// Type for generics /// and also error messages /// with unknown types VarType(String), } #[derive(Debug,PartialEq)] pub enum TypeError { UndefinedVariable(String), UnboundGeneric(String), InvalidOperator { operator: SExp, expected: Type, found: Type, }, InvalidArgList { arglist: SExp, expected: Type, found: Type, }, ArgumentsDontMatchGeneric { argtype: Type, generictype: Type, }, OtherError } use Type::*; impl Type { /// Tests if the type has no variable types. /// /// **Examples** /// ```rust /// use myslip::r#type::{*, Type::*, TypeError::*, util::*}; /// /// assert_eq!(Integer.is_concrete(), Ok(())); /// assert_eq!(Boolean.is_concrete(), Ok(())); /// assert_eq!( /// VarType("a".to_string()).is_concrete(), /// Err("a".to_string()) /// ); /// /// assert_eq!(arr(Integer, Integer).is_concrete(), Ok(())); /// assert_eq!(arr(Integer, Boolean).is_concrete(), Ok(())); /// assert_eq!( /// arr(VarType("b".to_string()), Integer).is_concrete(), /// Err("b".to_string()) /// ); /// /// assert_eq!( /// List(vec![Integer, Boolean, arr(Integer, Integer)]).is_concrete(), /// Ok(()) /// ); /// assert_eq!( /// List(vec![Integer, VarType("a".to_string()), Integer]) /// .is_concrete(), /// Err("a".to_string()) /// ); /// ``` pub fn is_concrete(&self) -> Result<(), String> { match self { Integer => Ok(()), Boolean => Ok(()), Arrow(a, b) => b.is_concrete().and_then(|_ok| a.is_concrete()), List(v) => { let mut res = Ok(()); for t in v { res = res.and_then(|_ok| t.is_concrete()); } res }, VarType(s) => Err(s.clone()), } } }