aboutsummaryrefslogtreecommitdiff
path: root/src/type/check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/type/check.rs')
-rw-r--r--src/type/check.rs121
1 files changed, 121 insertions, 0 deletions
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<Type, TypeError> {
+ self.type_check_ctx(HashMap::new())
+ }
+
+
+ fn type_check_ctx(&self, ctx: HashMap<String, Type>) -> Result<Type, TypeError> {
+ todo!();
+ }
+
+}