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, TypeError> { todo!() } }