summaryrefslogtreecommitdiff
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
parent58f30a0ce9e8bb0dde99edcbbaf8e1b7757e2ee6 (diff)
Reimplement checking of variable bindings
-rw-r--r--src/ast.rs6
-rw-r--r--src/semantic/translate.rs102
-rw-r--r--src/semantic/types.rs18
-rw-r--r--src/taiga.lalrpop3
4 files changed, 103 insertions, 26 deletions
diff --git a/src/ast.rs b/src/ast.rs
index 8b93e34..3cc68c1 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -85,8 +85,8 @@ pub enum Expression {
#[derive(Debug)]
pub struct RecordField {
- name: WithLocation<String>,
- ty: WithLocation<String>,
+ pub name: WithLocation<String>,
+ pub ty: WithLocation<String>,
}
impl RecordField {
@@ -98,7 +98,7 @@ impl RecordField {
#[derive(Debug)]
pub enum Ty {
Name(String),
- Array(Box<Ty>),
+ Array(Box<WithLocation<Ty>>),
Record(Vec<WithLocation<RecordField>>),
}
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),
+ }
+ }
}
diff --git a/src/taiga.lalrpop b/src/taiga.lalrpop
index afa6433..0c7fea0 100644
--- a/src/taiga.lalrpop
+++ b/src/taiga.lalrpop
@@ -29,7 +29,8 @@ Parameters: WithLocation<Vec<WithLocation<ast::RecordField>>> = {
Ty: WithLocation<ast::Ty> = {
<Name> => <>.map(|v| ast::Ty::Name(v)),
- "array" "of" <Name> => <>.map(|v| ast::Ty::Array(Box::new(ast::Ty::Name(v)))),
+ <l: @L> "array" "of" <n: Name> <r: @R> =>
+ WithLocation::new(ast::Ty::Array(Box::new(n.map(|v| ast::Ty::Name(v)))), l, r),
<RecordFields> => <>.map(|v| ast::Ty::Record(v)),
};