aboutsummaryrefslogtreecommitdiff
path: root/src/type/case.rs
blob: 2403acd09f56dd52eb3a60ca1dcffba0d1f04ff5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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!()
    }
}