summaryrefslogtreecommitdiff
path: root/src/semantic
diff options
context:
space:
mode:
authorDavid Li <li.davidm96@gmail.com>2017-11-06 09:00:14 -0500
committerDavid Li <li.davidm96@gmail.com>2017-11-06 09:00:14 -0500
commit48411d44fd742800348dace427217a9b5727138d (patch)
tree06edd036fcd1b67d3fa5805442a8c0055c7e9140 /src/semantic
parent58f30a0ce9e8bb0dde99edcbbaf8e1b7757e2ee6 (diff)
Reimplement checking of variable bindings
Diffstat (limited to 'src/semantic')
-rw-r--r--src/semantic/translate.rs102
-rw-r--r--src/semantic/types.rs18
2 files changed, 98 insertions, 22 deletions
diff --git a/src/semantic/translate.rs b/src/semantic/translate.rs
index cf1dcf8..43c0fb0 100644
--- a/src/semantic/translate.rs
+++ b/src/semantic/translate.rs
@@ -1,6 +1,6 @@
use ::ast::{self, WithLocation};
use super::environment;
-use super::types::Ty;
+use super::types::{self, Ty};
#[derive(Debug)]
pub enum TypeError {
@@ -16,8 +16,11 @@ type TypeEnvironment<'a> = environment::Environment<'a, String, Ty>;
pub type Result = ::std::result::Result<Ty, WithLocation<TypeError>>;
pub fn translate(program: &ast::Program) -> Result {
- let mut env = TypeEnvironment::new(None);
- trans_exp(&mut env, &*program.0)
+ let mut venv = TypeEnvironment::new(None);
+ let mut tenv = TypeEnvironment::new(None);
+ tenv.add_binding("int".into(), Ty::Int);
+ tenv.add_binding("string".into(), Ty::String);
+ trans_exp(&mut venv, &mut tenv, &*program.0)
}
macro_rules! err {
@@ -26,28 +29,85 @@ macro_rules! err {
}
}
-fn trans_exp<'a>(venv: &mut TypeEnvironment<'a>, exp: &WithLocation<ast::Expression>) -> Result {
+fn trans_ty<'a>(
+ venv: &mut TypeEnvironment<'a>,
+ tenv: &mut TypeEnvironment<'a>,
+ ty: &WithLocation<ast::Ty>) -> Result {
+ match ty.value {
+ ast::Ty::Name(ref name) => {
+ tenv.lookup(&name)
+ .map(|v| v.clone())
+ .ok_or(WithLocation::new(TypeError::UnboundName, ty.start, ty.end))
+ }
+ ast::Ty::Array(ref inner_ty) => {
+ trans_ty(venv, tenv, &inner_ty)
+ },
+ ast::Ty::Record(ref fields) => {
+ err!(ty, TypeError::Unimplemented)
+ // let result = vec![];
+ // for field in fields {
+ // result.push(types::RecordField::new(
+ // *field.name,
+ // trans_ty(venv, tenv, field.ty)?));
+ // }
+ // Ok(Ty::Record(result))
+ },
+ }
+}
+
+fn trans_decl<'a>(
+ venv: &mut TypeEnvironment<'a>,
+ tenv: &mut TypeEnvironment<'a>,
+ decl: &WithLocation<ast::Declaration>) -> Result {
+ match decl.declaration {
+ ast::DeclarationBody::Fun { .. } => {
+ err!(decl, TypeError::Unimplemented)
+ }
+ ast::DeclarationBody::Ty { ref ty } => {
+ err!(decl, TypeError::Unimplemented)
+ }
+ ast::DeclarationBody::Var { ref ty, ref value } => {
+ let actual_ty = trans_exp(venv, tenv, &value)?;
+ if let &Some(ref ty) = ty {
+ let decl_ty = trans_ty(venv, tenv, &ty)?;
+ if decl_ty != actual_ty {
+ return err!(ty, TypeError::Mismatch {
+ expected: decl_ty,
+ actual: actual_ty,
+ });
+ }
+ }
+ Ok(actual_ty)
+ }
+ }
+}
+
+fn trans_exp<'a>(
+ venv: &mut TypeEnvironment<'a>,
+ tenv: &mut TypeEnvironment<'a>,
+ exp: &WithLocation<ast::Expression>) -> Result {
use ast::Expression::*;
match &exp.value {
&Let(ref decls, ref body) => {
- err!(exp, TypeError::Unimplemented)
- // 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.name.clone(), decl_ty);
- // }
- // }
- // new_env.set_parent(venv);
- // trans_exp(&mut new_env, &*body)
+ let mut new_venv = TypeEnvironment::new(Some(venv));
+ let mut new_tenv = TypeEnvironment::new(Some(tenv));
+ for decl in decls.iter() {
+ let decl_ty = trans_decl(&mut new_venv, &mut new_tenv, decl)?;
+ match decl.declaration {
+ ast::DeclarationBody::Fun { .. } | ast::DeclarationBody::Var { .. } => {
+ new_venv.add_binding(decl.name.clone(), decl_ty);
+ }
+ ast::DeclarationBody::Ty { .. } => {
+ new_tenv.add_binding(decl.name.clone(), decl_ty);
+ }
+ }
+ }
+ trans_exp(&mut new_venv, &mut new_tenv, &*body)
},
&UnaryOp(ref op, ref operand) => {
use ast::UnaryOp::*;
- let operand_ty = trans_exp(venv, operand)?;
+ let operand_ty = trans_exp(venv, tenv, operand)?;
match op {
&Neg | &Pos => {
match operand_ty {
@@ -69,8 +129,8 @@ fn trans_exp<'a>(venv: &mut TypeEnvironment<'a>, exp: &WithLocation<ast::Express
},
&BinOp(ref op, ref left, ref right) => {
use ast::BinOp::*;
- let left_ty = trans_exp(venv, left)?;
- let right_ty = trans_exp(venv, right)?;
+ let left_ty = trans_exp(venv, tenv, left)?;
+ let right_ty = trans_exp(venv, tenv, right)?;
match op {
&Add => {
match (left_ty, right_ty) {
@@ -106,7 +166,7 @@ fn trans_exp<'a>(venv: &mut TypeEnvironment<'a>, exp: &WithLocation<ast::Express
&String(_) => Ok(Ty::String),
&Name(ref name) => {
if let Some(ty) = venv.lookup(name) {
- Ok(*ty)
+ Ok(ty.clone())
}
else {
err!(exp, TypeError::UnboundName)
diff --git a/src/semantic/types.rs b/src/semantic/types.rs
index 3e31b04..af6c971 100644
--- a/src/semantic/types.rs
+++ b/src/semantic/types.rs
@@ -1,7 +1,23 @@
-#[derive(Clone,Copy,Debug)]
+#[derive(Clone,Debug,Eq,PartialEq)]
pub enum Ty {
Int,
String,
Nil,
Unit,
+ Record(Vec<RecordField>),
+}
+
+#[derive(Clone,Debug,Eq,PartialEq)]
+pub struct RecordField {
+ name: String,
+ ty: Box<Ty>,
+}
+
+impl RecordField {
+ pub fn new(name: String, ty: Ty) -> RecordField {
+ RecordField {
+ name: name,
+ ty: Box::new(ty),
+ }
+ }
}