summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Li <li.davidm96@gmail.com>2017-11-06 21:12:56 -0500
committerDavid Li <li.davidm96@gmail.com>2017-11-06 21:12:56 -0500
commita90fdb63e8adb09dafcc050344c443d3b73838bc (patch)
treeaf62150d119aad693d20c97d8a503cdd6ff34c4c
parentb1ef87bc10b662d6e37f929fa86db7a20b44e7dd (diff)
Parse and typecheck function calls
-rw-r--r--src/ast.rs1
-rw-r--r--src/semantic/translate.rs49
-rw-r--r--src/semantic/types.rs1
-rw-r--r--src/taiga.lalrpop17
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<WithLocation<Expression>>),
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, &param.ty)?;
- new_venv.add_binding(param.name.value.clone(), decl_ty);
+ let arg_ty = trans_ty(&mut new_venv, &mut new_tenv, &param.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)]
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<ast::WithLocation<ast::Expression>> = {
<ExpressionBase> => <>,
};
+CallArgsList: Vec<WithLocation<ast::Expression>> = {
+ <exp: Expression> "," <rest: CallArgsList> => {
+ let mut rest = rest;
+ rest.push(*exp);
+ rest
+ },
+ <exp: Expression> "," => vec![*exp],
+ <exp: Expression> => vec![*exp],
+};
+
+CallArgs: Vec<WithLocation<ast::Expression>> = {
+ "(" <v: CallArgsList> ")" => v,
+ "(" ")" => vec![],
+};
+
ExpressionBase: Box<ast::WithLocation<ast::Expression>> = {
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))),
+ <l: @L> <func: Name> <args: CallArgs> <r: @R> =>
+ Box::new(WithLocation::new(ast::Expression::Call(func.value, args), l, r)),
Spanned<r"nil"> => Box::new(<>.map(|v| ast::Expression::Nil)),
<l: @L> "let" <d: DeclarationsList> "in" <e: Expression> "end" <r: @R> =>
Box::new(WithLocation::new(ast::Expression::Let(d, e), l, r)),