summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs2
-rw-r--r--src/semantic/analysis.rs248
-rw-r--r--src/semantic/mod.rs2
-rw-r--r--src/semantic/translate.rs248
4 files changed, 251 insertions, 249 deletions
diff --git a/src/main.rs b/src/main.rs
index bb12399..0579fc8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,7 +21,7 @@ fn main() {
let program = taiga::parse_Program(&input);
println!("{:?}", program);
if let Ok(program) = program {
- println!("{:?}", semantic::translate::translate(&program));
+ println!("{:?}", semantic::analysis::translate(&program));
}
}
else {
diff --git a/src/semantic/analysis.rs b/src/semantic/analysis.rs
new file mode 100644
index 0000000..21a9eb8
--- /dev/null
+++ b/src/semantic/analysis.rs
@@ -0,0 +1,248 @@
+// Copyright ⓒ 2017 David Li.
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use ::ast::{self, WithLocation};
+use super::environment;
+use super::types::{self, Ty};
+
+#[derive(Debug)]
+pub enum TypeError {
+ Unimplemented,
+ LengthMismatch {
+ expected: usize,
+ actual: usize,
+ },
+ Mismatch {
+ expected: Ty,
+ actual: Ty,
+ },
+ UnboundName,
+}
+
+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 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 {
+ ($exp: expr, $err: expr) => {
+ Err(WithLocation::new($err, $exp.start, $exp.end))
+ }
+}
+
+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) => {
+ let mut result = vec![];
+ for field in fields {
+ result.push(types::RecordField::new(
+ field.name.clone(),
+ 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 { ref ty, ref params, ref body } => {
+ let declared_ty = if let &Some(ref ty) = ty {
+ Some(ast::WithLocation::new(trans_ty(venv, tenv, &ty)?, ty.start, ty.end))
+ } else { None };
+
+ let mut new_venv = TypeEnvironment::new(Some(venv));
+ let mut new_tenv = TypeEnvironment::new(Some(tenv));
+ let mut arg_types = vec![];
+ for param in params.iter() {
+ let arg_ty = trans_ty(&mut new_venv, &mut new_tenv, &param.ty)?;
+ arg_types.push(arg_ty.clone());
+ new_venv.add_binding(param.name.value.clone(), arg_ty);
+ }
+
+ let body_ty = trans_exp(&mut new_venv, &mut new_tenv, &*body)?;
+
+ if let Some(decl_ty) = declared_ty {
+ if &decl_ty.value != &body_ty {
+ return err!(decl_ty, TypeError::Mismatch {
+ expected: decl_ty.value,
+ actual: body_ty,
+ });
+ }
+ }
+
+ Ok(Ty::Function(arg_types, Box::new(body_ty)))
+ }
+ ast::DeclarationBody::Ty { ref ty } => {
+ trans_ty(venv, tenv, ty)
+ }
+ 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) => {
+ 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)
+ },
+ &Call(ref name, ref args) => {
+ let mut arg_types = vec![];
+ for arg in args {
+ arg_types.push(trans_exp(venv, tenv, arg)?);
+ }
+
+ let fun_ty = venv.lookup(name)
+ .ok_or(WithLocation::new(TypeError::UnboundName,
+ exp.start, exp.end))?;
+ match fun_ty {
+ &Ty::Function(ref expected_args, ref result) => {
+ if expected_args.len() != arg_types.len() {
+ return err!(exp, TypeError::LengthMismatch {
+ expected: expected_args.len(),
+ actual: arg_types.len(),
+ });
+ }
+ for (i, (provided_ty, expected_ty)) in
+ arg_types.iter().zip(expected_args).enumerate() {
+ if provided_ty != expected_ty {
+ return err!(args[i], TypeError::Mismatch {
+ expected: expected_ty.clone(),
+ actual: provided_ty.clone(),
+ })
+ }
+ }
+ Ok((**result).clone())
+ },
+ otherwise => {
+ err!(exp, TypeError::Mismatch {
+ // TODO: better way to handle this
+ expected: Ty::Function(arg_types, Box::new(Ty::Nil)),
+ actual: otherwise.clone(),
+ })
+ }
+ }
+ },
+ &UnaryOp(ref op, ref operand) => {
+ use ast::UnaryOp::*;
+ let operand_ty = trans_exp(venv, tenv, operand)?;
+ match op {
+ &Neg | &Pos => {
+ match operand_ty {
+ Ty::Int => {
+ Ok(Ty::Int)
+ }
+ other => {
+ err!(operand, TypeError::Mismatch {
+ expected: Ty::Int,
+ actual: other,
+ })
+ }
+ }
+ }
+ &Not => {
+ err!(exp, TypeError::Unimplemented)
+ }
+ }
+ },
+ &BinOp(ref op, ref left, ref right) => {
+ use ast::BinOp::*;
+ let left_ty = trans_exp(venv, tenv, left)?;
+ let right_ty = trans_exp(venv, tenv, right)?;
+ match op {
+ &Add => {
+ match (left_ty, right_ty) {
+ (Ty::Int, Ty::Int) => {
+ Ok(Ty::Int)
+ }
+ (Ty::String, Ty::String) => {
+ Ok(Ty::String)
+ }
+ (Ty::Int, other) | (other, Ty::Int) => {
+ err!(right, TypeError::Mismatch {
+ expected: Ty::Int,
+ actual: other,
+ })
+ }
+ (Ty::String, other) | (other, Ty::String) => {
+ err!(right, TypeError::Mismatch {
+ expected: Ty::String,
+ actual: other,
+ })
+ }
+ _ => {
+ err!(exp, TypeError::Unimplemented)
+ }
+ }
+ }
+ _ => {
+ err!(exp, TypeError::Unimplemented)
+ }
+ }
+ },
+ &Number(_) => Ok(Ty::Int),
+ &String(_) => Ok(Ty::String),
+ &Name(ref name) => {
+ if let Some(ty) = venv.lookup(name) {
+ Ok(ty.clone())
+ }
+ else {
+ err!(exp, TypeError::UnboundName)
+ }
+ },
+ &Nil => {
+ Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end))
+ },
+ }
+}
diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs
index afc56ef..5fe773c 100644
--- a/src/semantic/mod.rs
+++ b/src/semantic/mod.rs
@@ -3,8 +3,10 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+pub mod analysis;
pub mod environment;
pub mod frame;
+pub mod ir;
pub mod temp;
pub mod translate;
pub mod types;
diff --git a/src/semantic/translate.rs b/src/semantic/translate.rs
index a5a9557..e69de29 100644
--- a/src/semantic/translate.rs
+++ b/src/semantic/translate.rs
@@ -1,248 +0,0 @@
-// Copyright ⓒ 2017 David Li.
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-use ::ast::{self, WithLocation};
-use super::environment;
-use super::types::{self, Ty};
-
-#[derive(Debug)]
-pub enum TypeError {
- Unimplemented,
- LengthMismatch {
- expected: usize,
- actual: usize,
- },
- Mismatch {
- expected: Ty,
- actual: Ty,
- },
- UnboundName,
-}
-
-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 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 {
- ($exp: expr, $err: expr) => {
- Err(WithLocation::new($err, $exp.start, $exp.end))
- }
-}
-
-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) => {
- let mut result = vec![];
- for field in fields {
- result.push(types::RecordField::new(
- field.name.clone(),
- 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 { ref ty, ref params, ref body } => {
- let declared_ty = if let &Some(ref ty) = ty {
- Some(ast::WithLocation::new(trans_ty(venv, tenv, &ty)?, ty.start, ty.end))
- } else { None };
-
- let mut new_venv = TypeEnvironment::new(Some(venv));
- let mut new_tenv = TypeEnvironment::new(Some(tenv));
- let mut arg_types = vec![];
- for param in params.iter() {
- let arg_ty = trans_ty(&mut new_venv, &mut new_tenv, &param.ty)?;
- arg_types.push(arg_ty.clone());
- new_venv.add_binding(param.name.value.clone(), arg_ty);
- }
-
- let body_ty = trans_exp(&mut new_venv, &mut new_tenv, &*body)?;
-
- if let Some(decl_ty) = declared_ty {
- if &decl_ty.value != &body_ty {
- return err!(decl_ty, TypeError::Mismatch {
- expected: decl_ty.value,
- actual: body_ty,
- });
- }
- }
-
- Ok(Ty::Function(arg_types, Box::new(body_ty)))
- }
- ast::DeclarationBody::Ty { ref ty } => {
- trans_ty(venv, tenv, ty)
- }
- 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) => {
- 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)
- },
- &Call(ref name, ref args) => {
- let mut arg_types = vec![];
- for arg in args {
- arg_types.push(trans_exp(venv, tenv, arg)?);
- }
-
- let fun_ty = venv.lookup(name)
- .ok_or(WithLocation::new(TypeError::UnboundName,
- exp.start, exp.end))?;
- match fun_ty {
- &Ty::Function(ref expected_args, ref result) => {
- if expected_args.len() != arg_types.len() {
- return err!(exp, TypeError::LengthMismatch {
- expected: expected_args.len(),
- actual: arg_types.len(),
- });
- }
- for (i, (provided_ty, expected_ty)) in
- arg_types.iter().zip(expected_args).enumerate() {
- if provided_ty != expected_ty {
- return err!(args[i], TypeError::Mismatch {
- expected: expected_ty.clone(),
- actual: provided_ty.clone(),
- })
- }
- }
- Ok((**result).clone())
- },
- otherwise => {
- err!(exp, TypeError::Mismatch {
- // TODO: better way to handle this
- expected: Ty::Function(arg_types, Box::new(Ty::Nil)),
- actual: otherwise.clone(),
- })
- }
- }
- },
- &UnaryOp(ref op, ref operand) => {
- use ast::UnaryOp::*;
- let operand_ty = trans_exp(venv, tenv, operand)?;
- match op {
- &Neg | &Pos => {
- match operand_ty {
- Ty::Int => {
- Ok(Ty::Int)
- }
- other => {
- err!(operand, TypeError::Mismatch {
- expected: Ty::Int,
- actual: other,
- })
- }
- }
- }
- &Not => {
- err!(exp, TypeError::Unimplemented)
- }
- }
- },
- &BinOp(ref op, ref left, ref right) => {
- use ast::BinOp::*;
- let left_ty = trans_exp(venv, tenv, left)?;
- let right_ty = trans_exp(venv, tenv, right)?;
- match op {
- &Add => {
- match (left_ty, right_ty) {
- (Ty::Int, Ty::Int) => {
- Ok(Ty::Int)
- }
- (Ty::String, Ty::String) => {
- Ok(Ty::String)
- }
- (Ty::Int, other) => {
- err!(right, TypeError::Mismatch {
- expected: Ty::Int,
- actual: other,
- })
- }
- (Ty::String, other) => {
- err!(right, TypeError::Mismatch {
- expected: Ty::String,
- actual: other,
- })
- }
- _ => {
- err!(exp, TypeError::Unimplemented)
- }
- }
- }
- _ => {
- err!(exp, TypeError::Unimplemented)
- }
- }
- },
- &Number(_) => Ok(Ty::Int),
- &String(_) => Ok(Ty::String),
- &Name(ref name) => {
- if let Some(ty) = venv.lookup(name) {
- Ok(ty.clone())
- }
- else {
- err!(exp, TypeError::UnboundName)
- }
- },
- &Nil => {
- Err(WithLocation::new(TypeError::Unimplemented, exp.start, exp.end))
- },
- }
-}