aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/type/case.rs211
1 files changed, 112 insertions, 99 deletions
diff --git a/src/type/case.rs b/src/type/case.rs
index 70597b6..5669e74 100644
--- a/src/type/case.rs
+++ b/src/type/case.rs
@@ -9,105 +9,7 @@ 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))
- /// ])
- /// );
- /// ```
- ///
- /// Vector matching should work without the rest pattern too:
- /// ```rust
- /// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
- /// use myslip::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
- /// assert_eq!(
- /// scons(var("h"), scons(2, Nil)).matches_type(&vecof(Integer)),
- /// Ok(vec![("h".to_string(), Integer)])
- /// );
- /// ```
- /// TODO: Nil / empty list
+ /// TODO? Nil / empty list
pub fn matches_type(
&self,
ty: &Type
@@ -134,6 +36,8 @@ impl SExp {
ctx: HashMap<String, Type>
) -> Result<Vec<(String, Type)>, TypeError> {
+ println!("checking if {} matches pattern {}", &ty, &self);
+
match (self, ty) {
(a, b) if a.infer_list_type(ctx.clone()) == Ok(b.clone()) =>
@@ -226,3 +130,112 @@ impl SExp {
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::sexp::{SExp::*, SLeaf::*, util::*};
+ use crate::r#type::{Type::*, util::*, TypeError::*, PatFail::*};
+
+ #[test]
+ fn test_type_atoms() {
+ assert_eq!(Atom(Int(1)).matches_type(&Integer), Ok(vec![]));
+ assert_eq!(Atom(True).matches_type(&Boolean), Ok(vec![]));
+ assert_eq!(Atom(Ty(Integer)).matches_type(&TypeLit), Ok(vec![]));
+ assert_eq!(Atom(Nil).matches_type(&NilType), Ok(vec![]));
+ }
+
+ #[test]
+ fn test_vector_match() {
+ assert_eq!(
+ scons(1, scons(2, Nil))
+ .matches_type(&List(vec![VecType, vecof(Integer)])),
+ Ok(vec![])
+ );
+ assert_eq!(
+ scons(var("a"), scons(var("b"), Nil))
+ .matches_type(&List(vec![VecType, vecof(Integer)])),
+ Ok(vec![
+ ("a".to_string(), Integer),
+ ("b".to_string(), Integer)
+ ])
+ );
+ assert_eq!(
+ scons(var("a"), scons(RestPat("b".to_string()), Nil))
+ .matches_type(&List(vec![VecType, vecof(Integer)])),
+ Ok(vec![
+ ("a".to_string(), Integer),
+ ("b".to_string(), List(vec![VecType, vecof(Integer)]))
+ ])
+ );
+ }
+
+ #[test]
+ fn test_list_match() {
+ assert_eq!(
+ scons(1, scons(2, Nil))
+ .matches_type(&List(vec![QuoteTy, List(vec![Integer, Integer])])),
+ Ok(vec![])
+ );
+ assert_eq!(
+ scons(var("a"), scons(var("b"), Nil))
+ .matches_type(&List(vec![QuoteTy, List(vec![Integer, Integer])])),
+ Ok(vec![
+ ("a".to_string(), Integer),
+ ("b".to_string(), Integer)
+ ])
+ );
+ assert_eq!(
+ scons(var("a"), scons(RestPat("b".to_string()), Nil))
+ .matches_type(&List(vec![QuoteTy, List(vec![Integer, Integer, Integer])])),
+ Ok(vec![
+ ("a".to_string(), Integer),
+ ("b".to_string(), List(vec![QuoteTy, List(vec![Integer, Integer])]))
+ ])
+ );
+ }
+
+ #[test]
+ fn test_mismatch_match() {
+ assert_eq!(
+ scons(1, scons(2, Nil))
+ .matches_type(&List(vec![QuoteTy, List(vec![Integer])])),
+ Err(InvalidPattern(TypeMismatch {
+ pattern: scons(1, scons(2, Nil)),
+ expected: List(vec![QuoteTy, List(vec![Integer])]),
+ found: List(vec![QuoteTy, List(vec![Integer, Integer])])
+ }))
+ );
+ }
+
+ #[test]
+ fn test_simple_wildcard_match() {
+ assert_eq!(
+ var("x").matches_type(&List(vec![QuoteTy, List(vec![Integer, Integer])])),
+ Ok(vec![("x".to_string(), List(vec![QuoteTy, List(vec![Integer, Integer])]))])
+ );
+ }
+
+ #[test]
+ fn test_invalid_pattern_match() {
+ assert_eq!(
+ scons(var("x"), scons(var("x"), Nil))
+ .matches_type(&List(vec![QuoteTy, List(vec![Integer, Integer])])),
+ Err(InvalidPattern(RepeatedVariable(
+ "x".to_string(),
+ scons(var("x"), scons(var("x"), Nil))
+ )))
+ );
+ }
+
+ #[test]
+ fn test_nil_match() {
+ assert_eq!(
+ Atom(Nil).matches_type(&List(vec![VecType, vecof(Boolean)])),
+ Ok(vec![])
+ );
+ assert_eq!(
+ Atom(Nil).matches_type(&List(vec![QuoteTy, List(vec![])])),
+ Ok(vec![])
+ );
+ }
+}