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/ast.rs | 6 +-- src/semantic/translate.rs | 102 ++++++++++++++++++++++++++++++++++++---------- src/semantic/types.rs | 18 +++++++- src/taiga.lalrpop | 3 +- 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, - ty: WithLocation, + pub name: WithLocation, + pub ty: WithLocation, } impl RecordField { @@ -98,7 +98,7 @@ impl RecordField { #[derive(Debug)] pub enum Ty { Name(String), - Array(Box), + Array(Box>), Record(Vec>), } 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), + } + } } 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>> = { Ty: WithLocation = { => <>.map(|v| ast::Ty::Name(v)), - "array" "of" => <>.map(|v| ast::Ty::Array(Box::new(ast::Ty::Name(v)))), + "array" "of" => + WithLocation::new(ast::Ty::Array(Box::new(n.map(|v| ast::Ty::Name(v)))), l, r), => <>.map(|v| ast::Ty::Record(v)), }; -- cgit v1.2.3