summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Li <li.davidm96@gmail.com>2017-11-05 11:09:25 -0500
committerDavid Li <li.davidm96@gmail.com>2017-11-05 11:09:25 -0500
commit44570e6b300961cdcf080b82e7cc1d89fc553b0a (patch)
tree2efa439003990350b1bce24373819765ccbe886d
parent1c62effe91b5e50d1dbbc79c01655abfb3c17e16 (diff)
Check types in bindings, unary operators
-rw-r--r--src/ast.rs6
-rw-r--r--src/semantic/environment.rs4
-rw-r--r--src/semantic/translate.rs66
-rw-r--r--src/semantic/types.rs2
4 files changed, 62 insertions, 16 deletions
diff --git a/src/ast.rs b/src/ast.rs
index c3925b0..d60edc0 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -75,9 +75,9 @@ pub enum Expression {
#[derive(Debug)]
pub struct VarDec {
- name: WithLocation<String>,
- type_: Option<String>,
- value: Box<WithLocation<Expression>>,
+ pub name: WithLocation<String>,
+ pub type_: Option<String>,
+ pub value: Box<WithLocation<Expression>>,
}
impl VarDec {
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,