aboutsummaryrefslogtreecommitdiff
path: root/src/type/check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/type/check.rs')
-rw-r--r--src/type/check.rs56
1 files changed, 51 insertions, 5 deletions
diff --git a/src/type/check.rs b/src/type/check.rs
index 9d7c52b..7a2d231 100644
--- a/src/type/check.rs
+++ b/src/type/check.rs
@@ -1,5 +1,5 @@
-use crate::r#type::{Type, TypeError, Type::*, TypeError::*, util::*};
+use crate::r#type::{Type, TypeError, Type::*, TypeError::*, PatFail::*, util::*};
use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*};
use std::collections::HashMap;
@@ -156,7 +156,7 @@ impl SExp {
///
/// assert_eq!(
/// parse_to_ast(
- /// "(case (1 2 3 true false) ((x 2 3 false true) (+ x 1)) ((0 0 0 true true) 0) (_ 1))"
+ /// "+ (case (quote 1 2 3 true false) ((x 2 3 false true) (+ x 1)) ((0 0 0 true true) 0) (_ 1)) 0"
/// ).unwrap().type_check(),
/// Ok(Integer)
/// );
@@ -251,8 +251,8 @@ impl SExp {
Atom(Ty(_)) => Ok(TypeLit),
Atom(Arr) => Ok(arr(List(vec![TypeLit, TypeLit]), TypeLit)),
Atom(Fun) => Err(FunAsAtom),
- Atom(Case) => todo!(),
- Atom(RestPat(_)) => todo!(),
+ Atom(Case) => Err(CaseAsAtom),
+ Atom(RestPat(_)) => Err(RestAsAtom),
SCons(op, l) => {
@@ -274,6 +274,52 @@ impl SExp {
return scons(op.clone(), l.clone()).get_fun_type(ctx);
}
+ // Case expressions
+ if let Some((scrutinee, patarms)) = scons(op.clone(), l.clone()).check_case() {
+ let scruty = scrutinee.infer_type(ctx.clone())?;
+ let scruty = match scruty {
+ List(v) if (
+ v.get(0) == Some(&QuoteTy)
+ || v.get(0) == Some(&VecType)
+ ) && v.get(1).is_some() =>
+ v[1].clone(),
+ t => t,
+ };
+ let mut ty: Option<Type> = None;
+ let mut has_wildcard = false;
+ for patandarm in patarms {
+ let (pat, arm) = match patandarm {
+ SCons(pat, arm) => Ok((*pat, *arm)),
+ _ => Err(InvalidPattern(NoArm(patandarm))),
+ }?;
+ let arm = match arm {
+ SCons(x, n) if *n == Atom(Nil) => *x,
+ t => t,
+ };
+ if let Atom(Var(_)) = pat {
+ has_wildcard = true;
+ }
+ let mut newctx = ctx.clone();
+ for (name, ty) in pat.matches_type(&scruty)? {
+ newctx.insert(name, ty);
+ }
+ match &ty {
+ None => ty = Some(arm.infer_type(newctx)?),
+ Some(t) => if arm.infer_type(newctx.clone())? != *t {
+ println!("different types: {}, {}", t, arm.infer_list_type(newctx)?);
+ return Err(OtherError);
+ },
+ }
+ }
+ if !has_wildcard {
+ return Err(NoWildcardInCase(scrutinee));
+ }
+ match ty {
+ Some(t) => return Ok(t),
+ None => return Err(OtherError),
+ }
+ }
+
// Normal operation
let opertype = (*op).infer_type(ctx.clone())?;
let argstype = (*l).infer_list_type(ctx)?;
@@ -333,7 +379,7 @@ impl SExp {
}
- fn infer_list_type(&self, ctx: HashMap<String, Type>) -> Result<Type, TypeError> {
+ pub fn infer_list_type(&self, ctx: HashMap<String, Type>) -> Result<Type, TypeError> {
let mut res = vec![];
for exp in self.clone().parts() {
res.push(exp.infer_type(ctx.clone())?);