diff options
author | David Li <li.davidm96@gmail.com> | 2017-11-06 21:12:56 -0500 |
---|---|---|
committer | David Li <li.davidm96@gmail.com> | 2017-11-06 21:12:56 -0500 |
commit | a90fdb63e8adb09dafcc050344c443d3b73838bc (patch) | |
tree | af62150d119aad693d20c97d8a503cdd6ff34c4c /src/semantic | |
parent | b1ef87bc10b662d6e37f929fa86db7a20b44e7dd (diff) |
Parse and typecheck function calls
Diffstat (limited to 'src/semantic')
-rw-r--r-- | src/semantic/translate.rs | 49 | ||||
-rw-r--r-- | src/semantic/types.rs | 1 |
2 files changed, 47 insertions, 3 deletions
diff --git a/src/semantic/translate.rs b/src/semantic/translate.rs index 617c832..a5a9557 100644 --- a/src/semantic/translate.rs +++ b/src/semantic/translate.rs @@ -10,6 +10,10 @@ use super::types::{self, Ty}; #[derive(Debug)] pub enum TypeError { Unimplemented, + LengthMismatch { + expected: usize, + actual: usize, + }, Mismatch { expected: Ty, actual: Ty, @@ -71,9 +75,11 @@ fn trans_decl<'a>( let mut new_venv = TypeEnvironment::new(Some(venv)); let mut new_tenv = TypeEnvironment::new(Some(tenv)); + let mut arg_types = vec![]; for param in params.iter() { - let decl_ty = trans_ty(&mut new_venv, &mut new_tenv, ¶m.ty)?; - new_venv.add_binding(param.name.value.clone(), decl_ty); + let arg_ty = trans_ty(&mut new_venv, &mut new_tenv, ¶m.ty)?; + arg_types.push(arg_ty.clone()); + new_venv.add_binding(param.name.value.clone(), arg_ty); } let body_ty = trans_exp(&mut new_venv, &mut new_tenv, &*body)?; @@ -87,7 +93,7 @@ fn trans_decl<'a>( } } - Ok(body_ty) + Ok(Ty::Function(arg_types, Box::new(body_ty))) } ast::DeclarationBody::Ty { ref ty } => { trans_ty(venv, tenv, ty) @@ -131,6 +137,43 @@ fn trans_exp<'a>( } trans_exp(&mut new_venv, &mut new_tenv, &*body) }, + &Call(ref name, ref args) => { + let mut arg_types = vec![]; + for arg in args { + arg_types.push(trans_exp(venv, tenv, arg)?); + } + + let fun_ty = venv.lookup(name) + .ok_or(WithLocation::new(TypeError::UnboundName, + exp.start, exp.end))?; + match fun_ty { + &Ty::Function(ref expected_args, ref result) => { + if expected_args.len() != arg_types.len() { + return err!(exp, TypeError::LengthMismatch { + expected: expected_args.len(), + actual: arg_types.len(), + }); + } + for (i, (provided_ty, expected_ty)) in + arg_types.iter().zip(expected_args).enumerate() { + if provided_ty != expected_ty { + return err!(args[i], TypeError::Mismatch { + expected: expected_ty.clone(), + actual: provided_ty.clone(), + }) + } + } + Ok((**result).clone()) + }, + otherwise => { + err!(exp, TypeError::Mismatch { + // TODO: better way to handle this + expected: Ty::Function(arg_types, Box::new(Ty::Nil)), + actual: otherwise.clone(), + }) + } + } + }, &UnaryOp(ref op, ref operand) => { use ast::UnaryOp::*; let operand_ty = trans_exp(venv, tenv, operand)?; diff --git a/src/semantic/types.rs b/src/semantic/types.rs index 25d9fb5..928d8c9 100644 --- a/src/semantic/types.rs +++ b/src/semantic/types.rs @@ -10,6 +10,7 @@ pub enum Ty { Nil, Unit, Record(Vec<RecordField>), + Function(Vec<Ty>, Box<Ty>), } #[derive(Clone,Debug,Eq,PartialEq)] |