diff options
-rw-r--r-- | src/sexp/case.rs | 18 | ||||
-rw-r--r-- | src/sexp/step.rs | 16 | ||||
-rw-r--r-- | src/type/conversion.rs | 94 | ||||
-rw-r--r-- | src/type/util.rs | 13 |
4 files changed, 119 insertions, 22 deletions
diff --git a/src/sexp/case.rs b/src/sexp/case.rs index 40310e4..0c3d82d 100644 --- a/src/sexp/case.rs +++ b/src/sexp/case.rs @@ -1,5 +1,5 @@ -use crate::sexp::{SExp, SExp::*, SLeaf::*}; +use crate::sexp::{SExp, SLeaf, SExp::*, SLeaf::*, util::*}; impl SExp { /** @@ -20,7 +20,7 @@ impl SExp { * scons(1, scons(scons(2, scons(3, Nil)), Nil)) * .matches_pat(&var("x")), * Some(vec![( - * "x".to_string(), + * Var("x".to_string()), * scons(1, scons(scons(2, scons(3, Nil)), Nil)) * )]) * ); @@ -34,8 +34,8 @@ impl SExp { * 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))) + * (Var("x".to_string()), Atom(Int(1))), + * (Var("y".to_string()), scons(2, scons(3, Nil))) * ]) * ); * ``` @@ -47,24 +47,24 @@ impl SExp { * 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))) + * (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<(String, SExp)>> { + 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![(name.clone(), a.clone())]), + (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![(name, *a2.clone())]), + Some(name) => Some(vec![(RestPat(name.clone()), *a2.clone())]), None => a2.matches_pat(b2), }; lefthand.zip(righthand) diff --git a/src/sexp/step.rs b/src/sexp/step.rs index 99925ac..9077401 100644 --- a/src/sexp/step.rs +++ b/src/sexp/step.rs @@ -352,9 +352,10 @@ impl SExp { return Ok(SExp::back_to_case(scrutinee.step()?, patarms)); } - let scrutinee = match scrutinee { - SCons(q, v) if *q == Atom(Quote) || *q == Atom(Vector) => *v, - t => t, + let (scrutinee, rest_pat_struct) = match scrutinee { + SCons(q, v) if *q == Atom(Quote) => (*v, Some(Quote)), + SCons(q, v) if *q == Atom(Vector) => (*v, Some(Vector)), + t => (t, None), }; for patarm in patarms { @@ -369,7 +370,14 @@ impl SExp { if let Some(ctx) = scrutinee.matches_pat(&pat) { for (name, value) in ctx { - arm = arm.subst(&name, &value); + arm = match name { + Var(name) => arm.subst(&name, &value), + RestPat(name) => match rest_pat_struct.clone() { + Some(kw) => arm.subst(&name, &scons(kw, value)), + None => arm.subst(&name, &value) + }, + _ => panic!("unreachable") + }; } return Ok(arm); } diff --git a/src/type/conversion.rs b/src/type/conversion.rs index 36e2038..37ebc46 100644 --- a/src/type/conversion.rs +++ b/src/type/conversion.rs @@ -21,6 +21,18 @@ impl Type { /// assert!(List(vec![Boolean, Boolean, Boolean]).aka(&vecof(vt("T")))); /// ``` /// + /// Also, because quotes and vectors have their operators hanging + /// with them, having a conversion (Vector/Quote X) -> X is convenient. + /// ```rust + /// use myslip::r#type::{Type::*, util::*}; + /// assert!( + /// List(vec![QuoteTy, List(vec![Integer, Integer])]).aka(&vecof(Integer)), + /// ); + /// assert!( + /// List(vec![List(vec![QuoteTy, List(vec![Integer, Integer])])]).aka(&vecof(Integer)), + /// ); + /// ``` + /// /// But of course it also should know when to fail: /// ```rust /// use myslip::r#type::{Type::*, util::*}; @@ -82,6 +94,18 @@ impl Type { (vt(name), ctx) }, + (List(v), b) if v.len() == 1 && *&v[0].aka(b) => (b.clone(), ctx), + + (List(v1), x) if !x.is_quoted_or_vectored_list() + && (v1.get(0) == Some(&VecType) || v1.get(0) == Some(&QuoteTy)) + && v1.get(1) != None => + { + match (v1.get(1), x) { + (Some(a), b) => a.lgst_ctx(&b, ctx), + _ => panic!("unreachable") + } + }, + (Arrow(a1, a2), Arrow(b1, b2)) => { let (t1, newctx) = a1.lgst_ctx(b1, ctx); ctx = newctx; @@ -90,10 +114,6 @@ impl Type { (arr(t1, t2), ctx) }, - //(VecOf(a), VecOf(b)) => { - // let (res, ctx) = a.lgst_ctx(b, ctx); - // (vecof(res), ctx) - //}, (List(v1), List(v2)) if v1.len() == v2.len() => { let mut res = vec![]; @@ -137,8 +157,6 @@ impl Type { (vecof(res), ctx) }, - (List(v), b) if v.len() == 1 && *&v[0].aka(b) => (b.clone(), ctx), - _ => (vt("T"), ctx) } @@ -176,6 +194,20 @@ impl Type { /// assert_eq!(List(vec![Integer]).into_type(&Integer), Ok(Integer)); /// ``` /// + /// Also, because quotes and vectors have their operators hanging + /// with them, having a conversion (Vector/Quote X) -> X is convenient. + /// ```rust + /// use myslip::r#type::{Type::*, util::*}; + /// assert_eq!( + /// List(vec![VecType, vecof(Integer)]).into_type(&vecof(Integer)), + /// Ok(vecof(Integer)) + /// ); + /// assert_eq!( + /// List(vec![List(vec![VecType, vecof(Integer)])]).into_type(&vecof(Integer)), + /// Ok(vecof(Integer)) + /// ); + /// ``` + /// /// Now this also needs to be able to hand generics: /// ```rust /// use myslip::r#type::{Type::*, util::*}; @@ -221,19 +253,28 @@ impl Type { (_, VarType(_)) => Ok(self), + (List(x), b) if x.len() == 1 && *&x[0].aka(b) => Ok(x[0].clone().into_type(b)?), + (Arrow(a1, a2), Arrow(b1, b2)) => { let t1 = a1.clone().into_type(b1)?; let t2 = a2.clone().into_type(b2)?; Ok(arr(t1, t2)) }, + (List(v), x) if !x.is_quoted_or_vectored_list() + && (v.get(0) == Some(&VecType) || v.get(0) == Some(&QuoteTy)) + && v.get(1) != None => + { + v[1].clone().into_type(x) + }, + (List(v1), List(v2)) if v1.len() == v2.len() => { let mut res = vec![]; for (t1, t2) in v1.into_iter().zip(v2) { res.push(t1.clone().into_type(&t2)?); } Ok(List(res)) - } + }, (List(v), VecOf(b)) => match v.get(0) { Some(first) => { @@ -251,8 +292,6 @@ impl Type { Err(()) }, }, - - (List(x), b) if x.len() == 1 && *&x[0].aka(b) => Ok(x[0].clone()), _ => Err(()) @@ -327,6 +366,43 @@ mod tests { } #[test] + fn test_removing_quote_and_vec() { + assert_eq!( + List(vec![List(vec![VecType, NilType])]).least_general_supertype(&NilType), + NilType + ); + assert_eq!( + List(vec![VecType, NilType]).least_general_supertype(&NilType), + NilType + ); + assert_eq!( + List(vec![QuoteTy, NilType]).least_general_supertype(&NilType), + NilType + ); + assert_eq!( + List(vec![VecType, vecof(Boolean)]) + .least_general_supertype( + &vecof(Boolean) + ), + vecof(Boolean) + ); + assert_eq!( + List(vec![List(vec![VecType, vecof(Boolean)])]) + .least_general_supertype( + &vecof(Boolean) + ), + vecof(Boolean) + ); + assert_eq!( + List(vec![QuoteTy, List(vec![Integer, Boolean])]) + .least_general_supertype( + &List(vec![Integer, Boolean]) + ), + List(vec![Integer, Boolean]) + ); + } + + #[test] fn test_conversion_in_general_supertypes() { assert_eq!( diff --git a/src/type/util.rs b/src/type/util.rs index ad85b79..d95629d 100644 --- a/src/type/util.rs +++ b/src/type/util.rs @@ -14,6 +14,19 @@ pub fn vecof(ty: impl Into<Box<Type>>) -> Type { VecOf(ty.into()) } +impl Type { + pub fn is_quoted_or_vectored_list(&self) -> bool { + match self { + List(v) => match v.get(0) { + Some(VecType) => true, + Some(QuoteTy) => true, + _ => false, + }, + _ => false, + } + } +} + use crate::sexp::{SExp::*, SLeaf::*}; impl SExp { pub fn get_fun_type(self, mut ctx: HashMap<String, Type>) -> Result<Type, TypeError> { |