schala/schala-lang/language/src/typechecking.rs

216 lines
5.4 KiB
Rust
Raw Normal View History

2018-02-21 02:31:28 -08:00
use std::rc::Rc;
2018-11-06 16:47:34 -08:00
use ast::*;
2018-11-08 20:30:17 -08:00
use util::ScopeStack;
2018-11-06 13:44:52 -08:00
2018-05-27 02:44:06 -07:00
pub type TypeName = Rc<String>;
2018-11-06 13:44:52 -08:00
2018-11-08 20:30:17 -08:00
pub struct TypeContext<'a> {
2018-11-09 02:05:59 -08:00
variable_map: ScopeStack<'a, Rc<String>, Type<()>>
2018-11-06 13:44:52 -08:00
}
type InferResult<T> = Result<T, TypeError>;
2018-11-06 16:47:34 -08:00
#[derive(Debug, Clone)]
2018-11-08 02:26:02 -08:00
struct TypeError { msg: String }
impl TypeError {
fn new<A>(msg: &str) -> InferResult<A> {
Err(TypeError { msg: msg.to_string() })
}
}
2018-11-06 16:47:34 -08:00
2018-11-07 13:44:28 -08:00
#[derive(Debug, Clone)]
2018-11-09 02:05:59 -08:00
enum Type<a> {
Var(a),
2018-11-07 15:39:40 -08:00
Const(TConst),
2018-11-09 02:05:59 -08:00
Arrow(Box<Type<a>>, Box<Type<a>>),
2018-11-09 00:21:34 -08:00
ExistentialVar(u32)
2018-11-08 02:26:02 -08:00
}
impl TypeIdentifier {
2018-11-09 02:05:59 -08:00
fn to_monotype(&self) -> Type<()> {
2018-11-08 20:30:17 -08:00
match self {
TypeIdentifier::Tuple(items) => unimplemented!(),
TypeIdentifier::Singleton(TypeSingletonName { name, .. }) => {
match &name[..] {
2018-11-09 02:05:59 -08:00
"Nat" => Type::Const(TConst::Nat),
"Int" => Type::Const(TConst::Int),
"Float" => Type::Const(TConst::Float),
"Bool" => Type::Const(TConst::Bool),
"String" => Type::Const(TConst::StringT),
2018-11-08 20:30:17 -08:00
_ => unimplemented!()
}
}
}
2018-11-08 02:26:02 -08:00
}
2018-11-07 03:39:31 -08:00
}
2018-11-06 16:47:34 -08:00
2018-11-07 15:39:40 -08:00
#[derive(Debug, Clone)]
enum TConst {
User(Rc<String>),
Unit,
Nat,
2018-11-07 16:39:32 -08:00
Int,
Float,
StringT,
2018-11-08 02:12:01 -08:00
Bool,
2018-11-07 15:39:40 -08:00
}
impl TConst {
fn user(name: &str) -> TConst {
TConst::User(Rc::new(name.to_string()))
}
}
2018-11-07 13:44:28 -08:00
#[derive(Debug, Clone)]
2018-11-07 03:39:31 -08:00
struct PolyType {
vars: Vec<Rc<String>>,
2018-11-09 02:05:59 -08:00
ty: Type<()>
2018-11-06 16:47:34 -08:00
}
2018-11-08 20:30:17 -08:00
impl<'a> TypeContext<'a> {
pub fn new() -> TypeContext<'a> {
TypeContext {
variable_map: ScopeStack::new(None),
}
2018-11-06 13:44:52 -08:00
}
2018-11-07 13:44:28 -08:00
pub fn typecheck(&mut self, ast: &AST) -> Result<String, String> {
2018-11-06 16:47:34 -08:00
match self.infer_ast(ast) {
2018-11-07 13:44:28 -08:00
Ok(t) => Ok(format!("{:?}", t)),
2018-11-06 16:47:34 -08:00
Err(err) => Err(format!("Type error: {:?}", err))
}
}
}
2018-11-08 20:30:17 -08:00
impl<'a> TypeContext<'a> {
2018-11-09 02:05:59 -08:00
fn infer_ast(&mut self, ast: &AST) -> InferResult<Type<()>> {
let mut output = Type::Const(TConst::Unit);
2018-11-07 03:39:31 -08:00
for statement in ast.0.iter() {
2018-11-09 00:21:34 -08:00
output = self.infer_statement(statement)?;
2018-11-07 03:39:31 -08:00
}
Ok(output)
}
2018-11-09 02:05:59 -08:00
fn infer_statement(&mut self, stmt: &Statement) -> InferResult<Type<()>> {
2018-11-09 00:21:34 -08:00
match stmt {
Statement::ExpressionStatement(ref expr) => self.infer_expr(expr),
Statement::Declaration(ref decl) => self.infer_decl(decl),
}
}
2018-11-09 02:05:59 -08:00
fn infer_expr(&mut self, expr: &Expression) -> InferResult<Type<()>> {
2018-11-07 03:39:31 -08:00
match expr {
2018-11-08 02:26:02 -08:00
Expression(expr_type, Some(type_anno)) => {
let tx = self.infer_expr_type(expr_type)?;
let ty = type_anno.to_monotype();
self.unify(&ty, &tx)
},
2018-11-07 03:39:31 -08:00
Expression(expr_type, None) => self.infer_expr_type(expr_type)
}
}
2018-11-09 02:05:59 -08:00
fn infer_decl(&mut self, expr: &Declaration) -> InferResult<Type<()>> {
Ok(Type::Const(TConst::user("unimplemented")))
2018-11-06 16:47:34 -08:00
}
2018-11-07 03:39:31 -08:00
2018-11-09 02:05:59 -08:00
fn infer_expr_type(&mut self, expr_type: &ExpressionType) -> InferResult<Type<()>> {
2018-11-07 03:39:31 -08:00
use self::ExpressionType::*;
2018-11-08 02:12:01 -08:00
Ok(match expr_type {
2018-11-09 02:05:59 -08:00
NatLiteral(_) => Type::Const(TConst::Nat),
FloatLiteral(_) => Type::Const(TConst::Float),
StringLiteral(_) => Type::Const(TConst::StringT),
BoolLiteral(_) => Type::Const(TConst::Bool),
2018-11-08 20:30:17 -08:00
Value(name) => {
//TODO handle the distinction between 0-arg constructors and variables at some point
// need symbol table for that
match self.variable_map.lookup(name) {
Some(ty) => ty.clone(),
None => return TypeError::new(&format!("Variable {} not found", name))
}
},
IfExpression { discriminator, body } => self.infer_if_expr(discriminator, body)?,
2018-11-08 02:26:02 -08:00
Call { f, arguments } => {
2018-11-09 02:05:59 -08:00
let tf: Type<()> = self.infer_expr(f)?; //has to be an Arrow Type
2018-11-08 02:26:02 -08:00
let targ = self.infer_expr(&arguments[0])?; // TODO make this work with functions with more than one arg
match tf {
2018-11-09 02:05:59 -08:00
Type::Arrow(t1, t2) => {
2018-11-08 02:26:02 -08:00
self.unify(&t1, &targ)?;
*t2.clone()
},
_ => return TypeError::new("not a function")
}
},
2018-11-09 00:21:34 -08:00
Lambda { params, type_anno, body } => {
let arg_type = unimplemented!();
let result_type = unimplemented!();
2018-11-09 02:05:59 -08:00
Type::Arrow(Box::new(arg_type), Box::new(result_type))
2018-11-09 00:21:34 -08:00
}
2018-11-09 02:05:59 -08:00
_ => Type::Const(TConst::user("unimplemented"))
2018-11-08 02:12:01 -08:00
})
}
2018-11-09 02:05:59 -08:00
fn infer_if_expr(&mut self, discriminator: &Discriminator, body: &IfExpressionBody) -> InferResult<Type<()>> {
2018-11-08 20:30:17 -08:00
let test = match discriminator {
Discriminator::Simple(expr) => expr,
_ => return TypeError::new("Dame desu")
};
let (then_clause, maybe_else_clause) = match body {
IfExpressionBody::SimpleConditional(a, b) => (a, b),
_ => return TypeError::new("Dont work")
};
unimplemented!()
}
2018-11-09 02:05:59 -08:00
fn infer_block(&mut self, block: &Block) -> InferResult<Type<()>> {
let mut output = Type::Const(TConst::Unit);
2018-11-09 00:21:34 -08:00
for statement in block.iter() {
output = self.infer_statement(statement)?;
}
Ok(output)
}
2018-11-09 02:05:59 -08:00
fn unify(&mut self, t1: &Type<()>, t2: &Type<()>) -> InferResult<Type<()>> {
2018-11-08 02:12:01 -08:00
unimplemented!()
2018-11-07 03:39:31 -08:00
}
2018-11-09 00:21:34 -08:00
2018-11-09 02:05:59 -08:00
fn allocate_existential(&mut self) -> Type<()> {
Type::ExistentialVar(0)
2018-11-09 00:21:34 -08:00
}
2018-11-06 16:47:34 -08:00
}
#[cfg(test)]
mod tests {
use super::*;
2018-11-07 16:39:32 -08:00
fn parse(input: &str) -> AST {
let tokens: Vec<::tokenizing::Token> = ::tokenizing::tokenize(input);
let mut parser = ::parsing::Parser::new(tokens);
parser.parse().unwrap()
}
macro_rules! type_test {
($input:expr, $correct:expr) => {
{
let mut tc = TypeContext::new();
let ast = parse($input);
tc.add_symbols(&ast);
assert_eq!($correct, tc.type_check(&ast).unwrap())
}
}
}
2018-11-06 16:47:34 -08:00
#[test]
fn basic_inference() {
2018-11-06 13:44:52 -08:00
}
}