From 2e17ad5361a86d004ca48419a0f69f9c298ec1e1 Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Mon, 11 Aug 2025 21:39:01 +0300 Subject: refactor: Added helper matches_pat for pattern matching --- src/sexp/case.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/sexp/case.rs (limited to 'src/sexp/case.rs') diff --git a/src/sexp/case.rs b/src/sexp/case.rs new file mode 100644 index 0000000..71f5007 --- /dev/null +++ b/src/sexp/case.rs @@ -0,0 +1,88 @@ + +use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*}; + +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![( + * "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![ + * ("x".to_string(), Atom(Int(1))), + * ("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![ + * ("x".to_string(), Atom(Int(1))), + * ("y".to_string(), scons(2, scons(3, Nil))) + * ]) + * ); + * ``` + */ + pub fn matches_pat(&self, pat: &SExp) -> Option> { + match (self, pat) { + + (a, b) if a == b => Some(vec![]), + + (a, Atom(Var(name))) => Some(vec![(name.clone(), 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![(name, *a2.clone())]), + None => a2.matches_pat(b2), + }; + lefthand.zip(righthand) + .map(|vs| vs.0.into_iter().chain(vs.1).collect()) + }, + + _ => todo!(), + + } + } + + fn check_res_pat(&self) -> Option { + match self { + SCons(a, b) => match (*a.clone(), *b.clone()) { + (Atom(RestPat(s)), Atom(Nil)) => Some(s), + _ => None + }, + _ => None + } + } +} -- cgit v1.2.3