diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-12 12:12:39 +0300 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2025-08-12 12:12:39 +0300 |
commit | db736d795b759edd913d96195747f0881c4e950f (patch) | |
tree | 14cdf8e53810162857ff3a6ee672b9fd8e6ccbff /src/type/case.rs | |
parent | 2e17ad5361a86d004ca48419a0f69f9c298ec1e1 (diff) | |
download | myslip-db736d795b759edd913d96195747f0881c4e950f.tar.gz myslip-db736d795b759edd913d96195747f0881c4e950f.zip |
test: added failing tests for pattern match typing and matches_type
Diffstat (limited to 'src/type/case.rs')
-rw-r--r-- | src/type/case.rs | 102 |
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!() + } +} |