From e35522189f5217987bc455d70c3b9056541ef8c6 Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Sat, 16 Aug 2025 02:04:09 +0300 Subject: feat: type conversion from (Vec/Quote X) -> X and add vec/quote to rest pattern substitutions --- src/type/conversion.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++----- src/type/util.rs | 13 +++++++ 2 files changed, 98 insertions(+), 9 deletions(-) (limited to 'src/type') 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(()) @@ -326,6 +365,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() { 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>) -> 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) -> Result { -- cgit v1.2.3