aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-14 12:17:41 +0300
committerJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-14 12:17:41 +0300
commit0975bff6ddcf48de4072561adea67a5c1cd4456f (patch)
treef77291d0430079d6927bf896c133e97a6e59c684
parent189d06730ae23770fbb970bf37eb0993edb8cd2d (diff)
downloadmyslip-0975bff6ddcf48de4072561adea67a5c1cd4456f.tar.gz
myslip-0975bff6ddcf48de4072561adea67a5c1cd4456f.zip
fix: step scrutinee of case & can instantiate empty vec
-rw-r--r--src/sexp/case.rs1
-rw-r--r--src/sexp/step.rs23
-rw-r--r--src/sexp/util.rs8
-rw-r--r--src/type/check.rs15
4 files changed, 45 insertions, 2 deletions
diff --git a/src/sexp/case.rs b/src/sexp/case.rs
index d78f7ad..eb98446 100644
--- a/src/sexp/case.rs
+++ b/src/sexp/case.rs
@@ -54,6 +54,7 @@ impl SExp {
* ```
*/
pub fn matches_pat(&self, pat: &SExp) -> Option<Vec<(String, SExp)>> {
+ println!("matchin {self} against {pat}");
match (self, pat) {
(a, b) if a == b => Some(vec![]),
diff --git a/src/sexp/step.rs b/src/sexp/step.rs
index 97675fa..bae47a5 100644
--- a/src/sexp/step.rs
+++ b/src/sexp/step.rs
@@ -286,6 +286,20 @@ impl SExp {
/// );
/// ```
///
+ /// **Pattern matching**
+ /// ```rust
+ /// use myslip::{sexp::{SExp::*, SLeaf::*, util::*}, r#type::{Type::*, util::*}};
+ /// use myslip::parse::parsetree::parse_to_ast;
+ ///
+ /// let exp = "case (+ 1 2) (3 true) (_ false)";
+ /// let exp = parse_to_ast(exp);
+ /// let exp = exp.and_then(|e| e.step());
+ /// let expshould = parse_to_ast("case 3 (3 true) (_ false)");
+ /// assert_eq!(exp, expshould);
+ /// let exp = exp.and_then(|e| e.step());
+ /// assert_eq!(exp, Ok(Atom(True)));
+ /// ```
+ ///
/// Shadowing:
/// ```rust
/// use myslip::sexp::{SExp::*, SLeaf::*, util::*};
@@ -352,6 +366,10 @@ impl SExp {
// case expressions
SCons(op, l) if scons(op.clone(), l.clone()).check_case().is_some() => {
let (scrutinee, patarms) = scons(op, l).check_case().unwrap();
+ if !scrutinee.is_value() {
+ return Ok(SExp::back_to_case(scrutinee.step()?, patarms));
+ // return scons(Case, scons(scrutinee.step()?))
+ }
let scrutinee = match scrutinee {
SCons(q, v) if *q == Atom(Quote) || *q == Atom(Vector) => *v,
@@ -627,6 +645,11 @@ impl SExp {
}
},
+ // Nil in list
+ SCons(op, l) if *op == Atom(Nil) => {
+ Ok(scons(Vector, Nil))
+ },
+
// Print
SCons(op, l) if *op == Atom(Print) => {
println!("{}", *l);
diff --git a/src/sexp/util.rs b/src/sexp/util.rs
index 3de45d4..aa7ae18 100644
--- a/src/sexp/util.rs
+++ b/src/sexp/util.rs
@@ -94,4 +94,12 @@ impl SExp {
_ => None,
}
}
+
+ pub fn back_to_case(scrutinee: SExp, arms: Vec<SExp>) -> SExp {
+ let mut res = Atom(Nil);
+ for arm in arms.into_iter().rev() {
+ res = scons(arm, res);
+ }
+ scons(Case, scons(scrutinee, res))
+ }
}
diff --git a/src/type/check.rs b/src/type/check.rs
index f842b4c..02b629c 100644
--- a/src/type/check.rs
+++ b/src/type/check.rs
@@ -218,10 +218,10 @@ impl SExp {
pub fn type_check(&self) -> Result<Type, TypeError> {
let res = self.infer_type(HashMap::new());
match res {
- Ok(res) => match res.is_concrete() {
+ Ok(res) => {println!("maybe unbound: {}", res); match res.is_concrete() {
Ok(()) => Ok(res),
Err(name) => Err(UnboundGeneric(name)),
- },
+ }},
e => e,
}
}
@@ -281,6 +281,17 @@ impl SExp {
return scons(op.clone(), l.clone()).get_fun_type(ctx);
}
+ // Nil vector
+ if (**op).clone() == Atom(Nil) {
+ return match (**l).clone() {
+ SCons(v, n) if *n == Atom(Nil) => match *v {
+ Atom(Ty(t)) => Ok(vecof(t)),
+ _ => Err(OtherError),
+ },
+ _ => Err(OtherError)
+ }
+ }
+
// Case expressions
if let Some((scrutinee, patarms)) = scons(op.clone(), l.clone()).check_case() {
let scruty = scrutinee.infer_type(ctx.clone())?;