From 9121a0b782d2cd6551a393f1d3a79c7b092e4873 Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Sat, 2 Aug 2025 17:53:09 +0300 Subject: Added tests for type_check. Implemented std::fmt::Display for many enums. Added type variants List(Type), and UndefinedType for use in error messages. Implemented type utility arr(a, b). --- src/type/check.rs | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/type/check.rs (limited to 'src/type/check.rs') diff --git a/src/type/check.rs b/src/type/check.rs new file mode 100644 index 0000000..3f3b864 --- /dev/null +++ b/src/type/check.rs @@ -0,0 +1,121 @@ + +use crate::r#type::{Type, TypeError}; +use crate::sexp::SExp; +use std::collections::HashMap; + +impl SExp { + + /// Returns the type of valid expressions. + /// Invalid expressions result in an error. + /// + /// Examples of simple expressions and their simple types: + /// ```rust + /// use melisp::{ + /// r#type::{*, Type::*, TypeError::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!(Atom(Int(1)).type_check(), Ok(Integer)); + /// ``` + /// + /// Quotes are given list types: + /// ```rust + /// use melisp::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!( + /// scons(Quote, scons(1, scons(2, Nil))).type_check(), + /// Ok(List(vec![Integer, Integer])) + /// ); + /// ``` + /// Though so is Nil given too: + /// ```rust + /// use melisp::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!( + /// Atom(Nil).type_check(), + /// Ok(List(vec![])) + /// ); + /// ``` + /// + /// Some common operators get arrow types: + /// ```rust + /// use melisp::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// assert_eq!(Atom(Add).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); + /// assert_eq!(Atom(Mul).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); + /// assert_eq!(Atom(Sub).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); + /// assert_eq!(Atom(Div).type_check(), Ok(arr(List(vec![Integer, Integer]), Integer))); + /// ``` + /// + /// Though perhaps the most important task of the type system + /// is to increase safety by being able to warn about errors + /// before evaluation. Here are some failing examples: + /// ```rust + /// use melisp::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// match scons(Mul, scons(1, Nil)).type_check() { + /// Err(InvalidArgList { .. }) => (), + /// _ => panic!( + /// "passing only 1 argument to '*' should result in InvalidArgList error" + /// ), + /// }; + /// + /// match scons(Sub, scons(1, scons(2, scons(3, Nil)))).type_check() { + /// Err(InvalidArgList { .. }) => (), + /// _ => panic!( + /// "passing over 2 arguments to '-' should result in InvalidArgList error" + /// ), + /// }; + /// + /// match scons(1, scons(2, Nil)).type_check() { + /// Err(InvalidOperator { .. }) => (), + /// _ => panic!( + /// "'1' as an operator should result in InvalidOperator error" + /// ), + /// }; + /// + /// match scons(Add, scons(Sub, scons(1, Nil))).type_check() { + /// Err(InvalidArgList { .. }) => (), + /// _ => panic!( + /// "passing '-' as an argument to '+' should return in InvalidArgList error" + /// ), + /// }; + /// ``` + /// + /// Also, free variables should result in an error + /// as their type can't be known by the type checker. + /// ```rust + /// use melisp::{ + /// r#type::{*, Type::*, TypeError::*, util::*}, + /// sexp::{SExp::*, SLeaf::*, util::*}, + /// }; + /// + /// match scons(Quote, scons(var("a"), Nil)).type_check() { + /// Err(UndefinedVariable(a)) if &a == "a" => (), + /// _ => panic!( + /// "passing a free variable in type check should result in UndefinedVariable error" + /// ), + /// }; + /// ``` + pub fn type_check(&self) -> Result { + self.type_check_ctx(HashMap::new()) + } + + + fn type_check_ctx(&self, ctx: HashMap) -> Result { + todo!(); + } + +} -- cgit v1.2.3