From 48411d44fd742800348dace427217a9b5727138d Mon Sep 17 00:00:00 2001
From: David Li 
Date: Mon, 6 Nov 2017 09:00:14 -0500
Subject: Reimplement checking of variable bindings
---
 src/semantic/translate.rs | 102 ++++++++++++++++++++++++++++++++++++----------
 src/semantic/types.rs     |  18 +++++++-
 2 files changed, 98 insertions(+), 22 deletions(-)
(limited to 'src/semantic')
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>;
 
 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) -> Result {
+fn trans_ty<'a>(
+    venv: &mut TypeEnvironment<'a>,
+    tenv: &mut TypeEnvironment<'a>,
+    ty: &WithLocation) -> 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) -> 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) -> 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 {
             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 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),
+}
+
+#[derive(Clone,Debug,Eq,PartialEq)]
+pub struct RecordField {
+    name: String,
+    ty: Box,
+}
+
+impl RecordField {
+    pub fn new(name: String, ty: Ty) -> RecordField {
+        RecordField {
+            name: name,
+            ty: Box::new(ty),
+        }
+    }
 }
-- 
cgit v1.2.3