aboutsummaryrefslogtreecommitdiff
path: root/src/type/case.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/type/case.rs')
-rw-r--r--src/type/case.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/type/case.rs b/src/type/case.rs
new file mode 100644
index 0000000..2403acd
--- /dev/null
+++ b/src/type/case.rs
@@ -0,0 +1,102 @@
+
+use crate::r#type::{Type, TypeError, Type::*, TypeError::*, PatFail::*, util::*};
+use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*};
+
+impl SExp {
+
+ /// Checks if this expression matches the given type,
+ /// returns all variable names bound by a respective case.
+ ///
+ /// Two equal values match:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// scons(1, scons(2, Nil))
+ /// .matches_type(&List(vec![Integer, Integer])),
+ /// Ok(vec![])
+ /// );
+ /// ```
+ ///
+ /// On the other hand, if values don't match, an invalid pattern
+ /// error should be thrown:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// scons(1, scons(2, Nil))
+ /// .matches_type(&List(vec![Integer])),
+ /// Err(InvalidPattern(TypeMismatch {
+ /// pattern: scons(1, scons(2, Nil)),
+ /// expected: List(vec![Integer]),
+ /// found: List(vec![Integer, Integer])
+ /// }))
+ /// );
+ /// ```
+ ///
+ /// A wildcard variable matches too and gets the correct type:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// var("x").matches_type(&List(vec![Integer, Integer])),
+ /// Ok(vec![("x".to_string(), List(vec![Integer, Integer]))])
+ /// );
+ /// ```
+ ///
+ /// Obviously that should also work for sub-expressions:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// scons(var("x"), scons(2, Nil)).matches_type(&List(vec![arr(Integer, Integer), Integer])),
+ /// Ok(vec![("x".to_string(), arr(Integer, Integer))])
+ /// );
+ /// ```
+ ///
+ /// If the wildcard variable is encountered multiple times,
+ /// an invalid operator error should be returned:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// scons(var("x"), scons(var("x"), Nil)).matches_type(&List(vec![Integer, Integer])),
+ /// Err(InvalidPattern(RepeatedVariable(
+ /// "x".to_string(),
+ /// scons(var("x"), scons(var("x"), Nil))
+ /// )))
+ /// );
+ /// ```
+ ///
+ /// Then there's also rest patterns which should be appropriately typed:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// scons(var("h"), scons(RestPat("t".to_string()), Nil))
+ /// .matches_type(&List(vec![arr(Integer, Integer), Integer, Integer, Integer])),
+ /// Ok(vec![
+ /// ("h".to_string(), arr(Integer, Integer)),
+ /// ("t".to_string(), List(vec![Integer, Integer, Integer]))
+ /// ])
+ /// );
+ /// ```
+ ///
+ /// They should also work with vectors:
+ /// ```rust
+ /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
+ /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+ /// assert_eq!(
+ /// scons(var("h"), scons(RestPat("t".to_string()), Nil))
+ /// .matches_type(&vecof(Integer)),
+ /// Ok(vec![
+ /// ("h".to_string(), Integer),
+ /// ("t".to_string(), vecof(Integer))
+ /// ])
+ /// );
+ /// ```
+ ///
+ pub fn matches_type(&self, ty: &Type) -> Result<Vec<(String, Type)>, TypeError> {
+ todo!()
+ }
+}