aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/sexp/case.rs18
-rw-r--r--src/sexp/step.rs16
-rw-r--r--src/type/conversion.rs94
-rw-r--r--src/type/util.rs13
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> {