diff options
Diffstat (limited to 'src/semantic')
-rw-r--r-- | src/semantic/environment.rs | 4 | ||||
-rw-r--r-- | src/semantic/translate.rs | 66 | ||||
-rw-r--r-- | src/semantic/types.rs | 2 |
3 files changed, 59 insertions, 13 deletions
diff --git a/src/semantic/environment.rs b/src/semantic/environment.rs index fab16b3..7876ad4 100644 --- a/src/semantic/environment.rs +++ b/src/semantic/environment.rs @@ -15,6 +15,10 @@ impl<'a, T: 'a, U: 'a> Environment<'a, T, U> } } + pub fn set_parent(&mut self, parent: &'a Environment<'a, T, U>) { + self.parent = Some(parent); + } + pub fn add_binding(&mut self, key: T, value: U) { self.bindings.insert(key, value); } diff --git a/src/semantic/translate.rs b/src/semantic/translate.rs index d3ebd2c..9da6411 100644 --- a/src/semantic/translate.rs +++ b/src/semantic/translate.rs @@ -9,6 +9,7 @@ pub enum TypeError { expected: Ty, actual: Ty, }, + UnboundName, } type TypeEnvironment<'a> = environment::Environment<'a, String, Ty>; @@ -19,23 +20,59 @@ pub fn translate(program: &ast::Program) -> Result { trans_exp(&mut env, &*program.0) } +macro_rules! err { + ($exp: expr, $err: expr) => { + Err(WithLocation::new($err, $exp.start, $exp.end)) + } +} + fn trans_exp<'a>(venv: &mut TypeEnvironment<'a>, exp: &WithLocation<ast::Expression>) -> Result { use ast::Expression::*; match &exp.value { &Let(ref decls, ref body) => { - Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end)) + let mut new_env = TypeEnvironment::new(None); + for decl in decls.iter() { + let decl_ty = trans_exp(venv, &*decl.value.value)?; + if let Some(_) = decl.value.type_ { + return err!(decl, TypeError::Unimplemented); + } + else { + new_env.add_binding(decl.value.name.value.clone(), decl_ty); + } + } + new_env.set_parent(venv); + trans_exp(&mut new_env, &*body) }, &UnaryOp(ref op, ref operand) => { - Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end)) + use ast::UnaryOp::*; + let operand_ty = trans_exp(venv, operand)?; + match op { + &Neg | &Pos => { + match operand_ty { + Ty::Int => { + Ok(Ty::Int) + } + other => { + err!(operand, TypeError::Mismatch { + expected: Ty::Int, + actual: other, + }) + } + } + } + &Not => { + err!(exp, TypeError::Unimplemented) + } + } }, &BinOp(ref op, ref left, ref right) => { use ast::BinOp::*; + let left_ty = trans_exp(venv, left)?; + let right_ty = trans_exp(venv, right)?; match op { &Add => { - let left = trans_exp(venv, left)?; - let right = trans_exp(venv, right)?; - match (left, right) { + match (left_ty, right_ty) { (Ty::Int, Ty::Int) => { Ok(Ty::Int) } @@ -43,31 +80,36 @@ fn trans_exp<'a>(venv: &mut TypeEnvironment<'a>, exp: &WithLocation<ast::Express Ok(Ty::String) } (Ty::Int, other) => { - Err(WithLocation::new(TypeError::Mismatch { + err!(right, TypeError::Mismatch { expected: Ty::Int, actual: other, - }, exp.start, exp.end)) + }) } (Ty::String, other) => { - Err(WithLocation::new(TypeError::Mismatch { + err!(right, TypeError::Mismatch { expected: Ty::String, actual: other, - }, exp.start, exp.end)) + }) } _ => { - Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end)) + err!(exp, TypeError::Unimplemented) } } } _ => { - Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end)) + err!(exp, TypeError::Unimplemented) } } }, &Number(_) => Ok(Ty::Int), &String(_) => Ok(Ty::String), &Name(ref name) => { - Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end)) + if let Some(ty) = venv.lookup(name) { + Ok(*ty) + } + else { + err!(exp, TypeError::UnboundName) + } }, &Nil => { Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end)) diff --git a/src/semantic/types.rs b/src/semantic/types.rs index 2d76387..3e31b04 100644 --- a/src/semantic/types.rs +++ b/src/semantic/types.rs @@ -1,4 +1,4 @@ -#[derive(Debug)] +#[derive(Clone,Copy,Debug)] pub enum Ty { Int, String, |