diff options
Diffstat (limited to 'src/semantic')
| -rw-r--r-- | src/semantic/translate.rs | 102 | ||||
| -rw-r--r-- | src/semantic/types.rs | 18 | 
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), +        } +    }  }  | 
