diff options
Diffstat (limited to 'src/type/check.rs')
-rw-r--r-- | src/type/check.rs | 56 |
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())?); |