From a90fdb63e8adb09dafcc050344c443d3b73838bc Mon Sep 17 00:00:00 2001 From: David Li Date: Mon, 6 Nov 2017 21:12:56 -0500 Subject: Parse and typecheck function calls --- src/ast.rs | 1 + src/semantic/translate.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++--- src/semantic/types.rs | 1 + src/taiga.lalrpop | 17 ++++++++++++++++ 4 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 447c249..f40c66b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -85,6 +85,7 @@ pub enum Expression { Number(u64), String(String), Name(String), + Call(String, Vec>), Nil, } 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), + Function(Vec, Box), } #[derive(Clone,Debug,Eq,PartialEq)] diff --git a/src/taiga.lalrpop b/src/taiga.lalrpop index 40830c6..9aa2f38 100644 --- a/src/taiga.lalrpop +++ b/src/taiga.lalrpop @@ -136,10 +136,27 @@ ExpressionSign: Box> = { => <>, }; +CallArgsList: Vec> = { + "," => { + let mut rest = rest; + rest.push(*exp); + rest + }, + "," => vec![*exp], + => vec![*exp], +}; + +CallArgs: Vec> = { + "(" ")" => v, + "(" ")" => vec![], +}; + ExpressionBase: Box> = { Num => Box::new(<>.map(|v| ast::Expression::Number(v))), String => Box::new(<>.map(|v| ast::Expression::String(v))), Name => Box::new(<>.map(|v| ast::Expression::Name(v))), + => + Box::new(WithLocation::new(ast::Expression::Call(func.value, args), l, r)), Spanned => Box::new(<>.map(|v| ast::Expression::Nil)), "let" "in" "end" => Box::new(WithLocation::new(ast::Expression::Let(d, e), l, r)), -- cgit v1.2.3