aboutsummaryrefslogtreecommitdiff
path: root/src/sexp/util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sexp/util.rs')
-rw-r--r--src/sexp/util.rs41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/sexp/util.rs b/src/sexp/util.rs
index aa7ae18..db400e9 100644
--- a/src/sexp/util.rs
+++ b/src/sexp/util.rs
@@ -87,6 +87,47 @@ impl SExp {
}
}
+ pub fn get_vars_bound_by_pattern(&self) -> Vec<String> {
+ match self {
+ Atom(Var(s)) => vec![s.clone()],
+ Atom(RestPat(s)) => vec![s.clone()],
+ SCons(a, b) =>
+ (*a).get_vars_bound_by_pattern()
+ .into_iter()
+ .chain((*b).get_vars_bound_by_pattern())
+ .collect(),
+ _ => vec![],
+ }
+ }
+
+ pub fn get_case_scrut_pats_and_arms(self) ->
+ Option<(SExp, Vec<(SExp, SExp)>)> {
+ let (scrutinee, patarms) = self.check_case()?;
+
+ let scrutinee = match scrutinee {
+ SCons(q, v) if *q == Atom(Quote) || *q == Atom(Vector) => *v,
+ t => t,
+ };
+
+ let mut res = vec![];
+ for patarm in patarms {
+ let (pat, arm) = match patarm {
+ SCons(pat, arm) => Some((*pat, *arm)),
+ _ => {
+ println!("warn: invalid structure in case arms,");
+ println!(" should be unreachable after type checking");
+ None
+ },
+ }?;
+ let arm = match arm {
+ SCons(x, n) if *n == Atom(Nil) => *x,
+ t => t,
+ };
+ res.push((pat, arm));
+ }
+ Some((scrutinee, res))
+ }
+
pub fn check_case(self) -> Option<(SExp, Vec<SExp>)> {
match &(self.parts())[..] {
[casekw, scrutinee, cases @ ..] if casekw.clone() == Atom(Case) =>