schala/src/schala_lang/typechecking.rs

148 lines
4.4 KiB
Rust
Raw Normal View History

2018-02-21 02:31:28 -08:00
use std::rc::Rc;
2018-02-22 03:21:58 -08:00
use std::collections::HashMap;
2018-02-21 02:31:28 -08:00
2018-02-23 01:49:37 -08:00
macro_rules! bx {
($e:expr) => { Box::new($e) }
}
2018-02-21 02:31:28 -08:00
use schala_lang::parsing;
2018-02-22 03:21:58 -08:00
pub struct TypeContext {
bindings: HashMap<Rc<String>, Type>
}
2018-02-21 02:31:28 -08:00
2018-02-21 03:39:40 -08:00
#[derive(Debug, PartialEq, Clone)]
2018-02-21 02:31:28 -08:00
pub enum Type {
Const(TConst),
2018-02-23 01:49:37 -08:00
Func(Box<Type>, Box<Type>),
Void
}
#[derive(Debug, PartialEq, Clone)]
pub enum TConst {
2018-02-22 19:59:53 -08:00
Unit,
2018-02-21 03:39:40 -08:00
Int,
Float,
StringT,
Bool,
Custom(String),
2018-02-21 02:31:28 -08:00
}
type TypeResult<T> = Result<T, String>;
impl TypeContext {
pub fn new() -> TypeContext {
2018-02-22 03:21:58 -08:00
TypeContext { bindings: HashMap::new() }
2018-02-21 02:31:28 -08:00
}
pub fn type_check_ast(&mut self, ast: &parsing::AST) -> TypeResult<Type> {
2018-02-22 19:59:53 -08:00
use self::Type::*; use self::TConst::*;
let mut ret_type = Const(Unit);
2018-02-21 02:31:28 -08:00
for statement in ast.0.iter() {
ret_type = self.type_check_statement(statement)?;
}
Ok(ret_type)
}
fn type_check_statement(&mut self, statement: &parsing::Statement) -> TypeResult<Type> {
2018-02-21 03:39:40 -08:00
println!("statement should be: {:?}", statement);
2018-02-21 02:31:28 -08:00
use self::parsing::Statement::*;
match statement {
2018-02-22 19:59:53 -08:00
&ExpressionStatement(ref expr) => self.infer(expr),
2018-02-22 03:21:58 -08:00
&Declaration(ref decl) => self.add_declaration(decl),
2018-02-21 02:31:28 -08:00
}
}
2018-02-22 03:21:58 -08:00
fn add_declaration(&mut self, decl: &parsing::Declaration) -> TypeResult<Type> {
use self::parsing::Declaration::*;
2018-02-21 02:31:28 -08:00
use self::Type::*;
2018-02-22 03:21:58 -08:00
match decl {
&Binding { ref name, ref expr, .. } => {
2018-02-22 19:59:53 -08:00
let ty = self.infer(expr)?;
2018-02-22 03:21:58 -08:00
self.bindings.insert(name.clone(), ty);
},
_ => return Err(format!("other formats not done"))
}
Ok(Void)
2018-02-21 02:31:28 -08:00
}
2018-02-22 19:59:53 -08:00
fn infer(&mut self, expr: &parsing::Expression) -> TypeResult<Type> {
2018-02-21 03:39:40 -08:00
use self::parsing::Expression;
match expr {
&Expression(ref e, Some(ref anno)) => {
let anno_ty = self.type_from_anno(anno)?;
2018-02-22 03:21:58 -08:00
let ty = self.infer_exprtype(&e)?;
self.unify(ty, anno_ty)
},
2018-02-22 03:21:58 -08:00
&Expression(ref e, None) => self.infer_exprtype(e)
2018-02-21 14:14:24 -08:00
}
}
2018-02-22 03:21:58 -08:00
fn infer_exprtype(&mut self, expr: &parsing::ExpressionType) -> TypeResult<Type> {
2018-02-21 14:14:24 -08:00
use self::parsing::ExpressionType::*;
use self::Type::*; use self::TConst::*;
match expr {
&IntLiteral(_) => Ok(Const(Int)),
&FloatLiteral(_) => Ok(Const(Float)),
&StringLiteral(_) => Ok(Const(StringT)),
&BoolLiteral(_) => Ok(Const(Bool)),
2018-02-23 01:49:37 -08:00
&BinExp(ref op, ref lhs, ref rhs) => { /* remember there are both the haskell convention talk and the write you a haskell ways to do this! */
match self.infer_optype(op)? {
Func(box t1, box Func(box t2, box t3)) => {
let lhs_ty = self.infer(lhs)?;
let rhs_ty = self.infer(rhs)?;
self.unify(t1, lhs_ty)?;
self.unify(t2, rhs_ty)?;
Ok(t3)
},
other => return Err(format!("{:?} is not a binary function type", other))
}
2018-02-22 19:59:53 -08:00
},
/*
BinExp(Operation, Box<Expression>, Box<Expression>),
PrefixExp(Operation, Box<Expression>),
TupleLiteral(Vec<Expression>),
Value(Rc<String>, Vec<(Rc<String>, Expression)>),
Call {
f: Box<Expression>,
arguments: Vec<Expression>,
},
Index {
indexee: Box<Expression>,
indexers: Vec<Expression>,
},
IfExpression(Box<Expression>, Vec<Statement>, Option<Vec<Statement>>),
MatchExpression(Box<Expression>, Vec<MatchArm>),
ForExpression
*/
2018-02-21 14:14:24 -08:00
_ => Err(format!("Type not yet implemented"))
2018-02-21 03:39:40 -08:00
}
}
2018-02-22 19:59:53 -08:00
fn infer_optype(&mut self, _op: &parsing::Operation) -> TypeResult<Type> {
use self::Type::*; use self::TConst::*;
//this is a shim; not all ops are binops from int -> int -> int
2018-02-23 01:49:37 -08:00
Ok(Func(bx!(Const(Int)), bx!(Func(bx!(Const(Int)), bx!(Const(Int))))))
2018-02-22 19:59:53 -08:00
}
fn type_from_anno(&mut self, anno: &parsing::TypeName) -> TypeResult<Type> {
use self::parsing::TypeSingletonName;
2018-02-21 18:12:46 -08:00
use self::parsing::TypeName::*;
use self::Type::*; use self::TConst::*;
2018-02-21 18:12:46 -08:00
Ok(match anno {
&Tuple(_) => return Err(format!("Tuples not yet implemented")),
&Singleton(ref name) => match name {
2018-02-22 00:31:13 -08:00
&TypeSingletonName { ref name, .. } => match &name[..] {
"Int" => Const(Int),
"Float" => Const(Float),
"Bool" => Const(Bool),
"String" => Const(StringT),
n => Const(Custom(n.to_string()))
2018-02-21 18:12:46 -08:00
}
}
})
2018-02-21 02:31:28 -08:00
}
fn unify(&mut self, t1: Type, t2: Type) -> TypeResult<Type> {
use self::Type::*;// use self::TConst::*;
match (t1, t2) {
(Const(ref a), Const(ref b)) if a == b => Ok(Const(a.clone())),
(a, b) => Err(format!("Types {:?} and {:?} don't unify", a, b))
}
}
2018-02-21 02:31:28 -08:00
}