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
|
use crate::sexp::{SExp, SLeaf, SExp::*, SLeaf::*};
impl SExp {
/**
* Matches this expression against the given pattern,
* that may contain RestPats and variables.
* upon successful match, variable bindings are returned.
*
* Two equal values match:
* ```rust
* use myslip::sexp::{SExp::*, SLeaf::*, util::*};
* assert_eq!(scons(1, Nil).matches_pat(&scons(1, Nil)), Some(vec![]));
* ```
* A variable (wildcard) pattern matches the whole expression:
* ```rust
* use myslip::sexp::{SExp::*, SLeaf::*, util::*};
*
* assert_eq!(
* scons(1, scons(scons(2, scons(3, Nil)), Nil))
* .matches_pat(&var("x")),
* Some(vec![(
* Var("x".to_string()),
* scons(1, scons(scons(2, scons(3, Nil)), Nil))
* )])
* );
* ```
* If a variable has a similar place in structure, it matches
* the corresponding part:
* ```rust
* use myslip::sexp::{SExp::*, SLeaf::*, util::*};
*
* assert_eq!(
* scons(1, scons(scons(2, scons(3, Nil)), Nil))
* .matches_pat(&scons(var("x"), scons(var("y"), Nil))),
* Some(vec![
* (Var("x".to_string()), Atom(Int(1))),
* (Var("y".to_string()), scons(2, scons(3, Nil)))
* ])
* );
* ```
* Rest patterns:
* ```rust
* use myslip::sexp::{SExp::*, SLeaf::*, util::*};
*
* assert_eq!(
* scons(1, scons(2, scons(3, Nil)))
* .matches_pat(&scons(var("x"), scons(RestPat("y".to_string()), Nil))),
* Some(vec![
* (Var("x".to_string()), Atom(Int(1))),
* (RestPat("y".to_string()), scons(2, scons(3, Nil)))
* ])
* );
* ```
*/
pub fn matches_pat(&self, pat: &SExp) -> Option<Vec<(SLeaf, SExp)>> {
match (self, pat) {
(a, b) if a == b => Some(vec![]),
(a, Atom(Var(name))) => Some(vec![(Var(name.to_string()), a.clone())]),
(SCons(a1, a2), SCons(b1, b2)) => {
let lefthand = a1.matches_pat(b1);
let checkres = (*b2).check_res_pat();
let righthand = match checkres {
Some(name) => Some(vec![(RestPat(name.clone()), *a2.clone())]),
None => a2.matches_pat(b2),
};
lefthand.zip(righthand)
.map(|vs| vs.0.into_iter().chain(vs.1).collect())
},
_ => None,
}
}
fn check_res_pat(&self) -> Option<String> {
match self {
SCons(a, b) => match (*a.clone(), *b.clone()) {
(Atom(RestPat(s)), Atom(Nil)) => Some(s),
_ => None
},
_ => None
}
}
}
|