use std::fmt; use crate::r#type::{Type, TypeError, FunDefError, Type::*, TypeError::*, FunDefError::*}; impl fmt::Display for Type { /// Formats the type for display to the programmer /// using this programming language. /// /// Examples: /// ```rust /// use myslip::r#type::{Type::*, util::*}; /// assert_eq!(Integer.to_string(), "int".to_string()); /// assert_eq!(Boolean.to_string(), "bool".to_string()); /// assert_eq!(arr(Integer, Boolean).to_string(), "(int -> bool)".to_string()); /// assert_eq!(List(vec![Integer, Boolean, Integer]).to_string(), "(int bool int)".to_string()); /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Integer => write!(f, "{}", "int"), Boolean => write!(f, "{}", "bool"), QuoteTy => write!(f, "{}", "Quote"), VecType => write!(f, "{}", "Vector"), LetType => write!(f, "{}", "Let"), NilType => write!(f, "()"), TypeLit => write!(f, "[type literal]"), VecOf(ty) => write!(f, "({} ... {})", *ty, *ty), Arrow(a, b) => write!(f, "({} -> {})", a, b), List(types) => write!( f, "({})", types.into_iter() .map(|t| t.to_string()) .collect::>() .join(" ") ), VarType(name) => write!(f, "{}", name), } } } impl fmt::Display for TypeError { /// Formats this type error for display to humans. /// /// Examples: /// ```rust /// use myslip::r#type::{TypeError::*, Type::*, util::*}; /// use myslip::sexp::{SExp, SExp::*, SLeaf::*, util::*}; /// /// assert_eq!( /// UndefinedVariable(String::from("x")).to_string(), /// "undefined variable: 'x'".to_string() /// ); /// assert_eq!( /// InvalidOperator { /// operator: Atom(Int(1)), /// expected: arr(VarType("?".to_string()), VarType("?".to_string())), /// found: Integer /// }.to_string(), /// "invalid operator: '1'\nexpected: '(? -> ?)'\nfound: 'int'".to_string() /// ); /// assert_eq!( /// InvalidArgList { /// arglist: scons(1, scons(2, scons(3, Nil))), /// expected: List(vec![Integer, Integer]), /// found: List(vec![Integer, Integer, Integer]), /// }.to_string(), /// "invalid argument list: '(1 2 3)'\nexpected: '(int int)'\nfound: '(int int int)'".to_string() /// ); /// assert_eq!( /// UnboundGeneric(String::from("?")).to_string(), /// "unbound generic type: '?'".to_string() /// ); /// assert_eq!( /// ArgumentsDontMatchGeneric { /// argtype: Integer, /// generictype: arr(VarType("T".to_string()), Integer) /// }.to_string(), /// "incompatible argument type 'int' and generic operator type '(T -> int)'".to_string() /// ); /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { UndefinedVariable(name) => write!(f, "undefined variable: '{}'", name), UnboundGeneric(name) => write!(f, "unbound generic type: '{}'", name), InvalidOperator { operator, expected, found } => { write!( f, "invalid operator: '{}'\nexpected: '{}'\nfound: '{}'", operator, expected, found ) }, InvalidArgList { arglist, expected, found } => { write!( f, "invalid argument list: '{}'\nexpected: '{}'\nfound: '{}'", arglist, expected, found ) }, ArgumentsDontMatchGeneric { argtype, generictype } => { write!( f, "incompatible argument type '{}' and generic operator type '{}'", argtype, generictype ) }, LetAsOperator(letexp) => { write!( f, "let used as operator instead of generating an operator: maybe try '({} ...)' instead", letexp ) }, FunAsAtom => write!(f, "'fn' used as atom doesn't make sense"), InvalidFunDef(exp, err) => write!(f, "invalid function definition '{exp}': {err}"), OtherError => write!(f, "uncategorized error"), } } } impl fmt::Display for FunDefError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { NoFunToken => write!( f, "no '{}'-token at start of definition", crate::sexp::SLeaf::Fun ), NoArgumentList => write!( f, "no list of argument names" ), NoTypeList => write!( f, "no list of argument types" ), NoReturnType => write!( f, "no return type supplied" ), NoFunctionBody => write!( f, "function has no body" ), InvalidArgumentList => write!(f, "invalid argument list"), InvalidTypeList => write!(f, "invalid argument type list"), InvalidReturnType => write!(f, "invalid return type"), } } }