schala/schala-lang/src/typechecking.rs

348 lines
9.2 KiB
Rust
Raw Normal View History

2018-02-21 02:31:28 -08:00
use std::rc::Rc;
2018-05-16 02:16:58 -07:00
use std::collections::{HashSet, HashMap};
2018-05-17 00:36:51 -07:00
use std::collections::hash_set::Union;
use std::iter::Iterator;
//use std::char;
2018-03-01 22:32:38 -08:00
use std::fmt;
use std::fmt::Write;
2018-02-21 02:31:28 -08:00
2018-03-03 11:52:07 -08:00
use itertools::Itertools;
2018-05-17 00:36:51 -07:00
/* GIANT TODO - use the rust im crate, unless I make this code way less haskell-ish after it's done
*/
2018-03-23 18:43:43 -07:00
use parsing;
2018-02-21 02:31:28 -08:00
pub struct TypeContext {
2018-02-27 03:01:05 -08:00
bindings: HashMap<Rc<String>, Type>,
2018-05-14 09:46:25 -07:00
pub symbol_table: SymbolTable
}
//cf. p. 150 or so of Language Implementation Patterns
2018-05-14 15:01:37 -07:00
pub struct SymbolTable {
pub values: HashMap<Rc<String>, Symbol> //TODO this will eventually have real type information
}
impl SymbolTable {
fn new() -> SymbolTable {
SymbolTable { values: HashMap::new() }
}
}
#[derive(Debug)]
2018-05-14 15:01:37 -07:00
pub struct Symbol {
2018-05-13 15:54:15 -07:00
pub name: Rc<String>,
2018-05-15 23:48:36 -07:00
pub spec: SymbolSpec,
}
#[derive(Debug)]
pub enum SymbolSpec {
Func, Custom(String)
2018-02-22 03:21:58 -08:00
}
2018-02-21 02:31:28 -08:00
2018-05-15 23:58:06 -07:00
/* real meat of type stuff here */
2018-05-16 02:16:58 -07:00
#[derive(Debug, PartialEq, Clone)]
enum MonoType {
Const(TypeConst),
Var(Rc<String>),
Function(Box<MonoType>, Box<MonoType>),
}
#[derive(Debug, PartialEq, Clone)]
enum TypeConst {
Unit,
Nat,
Int,
Float,
StringT,
Bool,
Tuple(Vec<MonoType>),
}
2018-05-17 00:36:51 -07:00
impl MonoType {
fn free_vars(&self) -> HashSet<Rc<String>> {
use self::MonoType::*;
match self {
Const(_) => HashSet::new(),
Var(a) => {
let mut h = HashSet::new();
h.insert(a.clone());
h
},
Function(a, b) => {
a.free_vars().union(&b.free_vars()).cloned().collect()
},
}
}
2018-05-17 00:48:48 -07:00
//TODO maybe this should be type self, and consume?
fn apply_substitution(&self, s: &Substitution) -> MonoType {
use self::MonoType::*;
match self {
Const(t) => Const(t.clone()),
Var(a) => s.0.get(a).map(|x| x.clone()).unwrap_or(Var(a.clone())),
Function(a, b) => Function(
Box::new(a.apply_substitution(s)),
Box::new(b.apply_substitution(s))
)
}
}
2018-05-17 00:36:51 -07:00
}
2018-05-16 02:16:58 -07:00
#[derive(Debug, PartialEq, Clone)]
struct PolyType(HashSet<Rc<String>>, MonoType);
2018-05-15 23:58:06 -07:00
2018-05-17 00:36:51 -07:00
impl PolyType {
fn free_vars(&self) -> HashSet<Rc<String>> {
let mtype = self.1.free_vars();
self.0.difference(&mtype).cloned().collect()
}
2018-05-17 00:48:48 -07:00
fn apply_substitution(&self, s: &Substitution) -> PolyType {
unimplemented!()
}
2018-05-17 00:36:51 -07:00
}
#[derive(Debug, PartialEq, Clone)]
struct Substitution(HashMap<Rc<String>, MonoType>);
2018-02-21 03:39:40 -08:00
#[derive(Debug, PartialEq, Clone)]
2018-02-21 02:31:28 -08:00
pub enum Type {
2018-05-16 01:08:06 -07:00
Const(TConstOld),
2018-02-23 01:49:37 -08:00
Func(Box<Type>, Box<Type>),
}
2018-05-15 21:47:08 -07:00
#[derive(Debug, PartialEq, Clone)]
2018-05-16 01:08:06 -07:00
pub enum TConstOld {
2018-05-15 21:47:08 -07:00
Nat,
Int,
Float,
StringT,
Bool,
Custom(String),
}
2018-03-01 22:32:38 -08:00
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2018-05-15 21:47:08 -07:00
write!(f, "{:?}", self)
2018-03-01 22:32:38 -08:00
}
}
2018-05-15 23:58:06 -07:00
/* TODO this should just check the name against a map, and that map should be pre-populated with
* types */
impl parsing::TypeName {
fn to_type(&self) -> TypeResult<Type> {
2018-05-15 23:58:06 -07:00
use self::parsing::TypeSingletonName;
use self::parsing::TypeName::*;
2018-05-16 01:08:06 -07:00
use self::Type::*; use self::TConstOld::*;
Ok(match self {
2018-05-15 23:58:06 -07:00
Tuple(_) => return Err(format!("Tuples not yet implemented")),
Singleton(name) => match name {
TypeSingletonName { name, .. } => match &name[..] {
2018-05-16 01:08:06 -07:00
/*
2018-05-12 01:44:03 -07:00
"Nat" => Const(Nat),
"Int" => Const(Int),
"Float" => Const(Float),
"Bool" => Const(Bool),
"String" => Const(StringT),
2018-05-16 01:08:06 -07:00
*/
n => Const(Custom(n.to_string()))
}
}
})
}
}
pub type TypeResult<T> = Result<T, String>;
2018-02-21 02:31:28 -08:00
impl TypeContext {
pub fn new() -> TypeContext {
TypeContext { bindings: HashMap::new(), /*type_var_count: 0*/ symbol_table: SymbolTable::new() }
2018-02-28 05:45:20 -08:00
}
2018-02-26 21:43:53 -08:00
2018-05-15 22:08:37 -07:00
/* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem
* later */
2018-02-27 03:01:05 -08:00
pub fn add_top_level_types(&mut self, ast: &parsing::AST) -> TypeResult<()> {
use self::parsing::{Statement, TypeName, Variant, TypeSingletonName, TypeBody};
2018-02-27 03:01:05 -08:00
use self::parsing::Declaration::*;
2018-03-03 11:32:38 -08:00
use self::Type::*;
2018-02-27 03:01:05 -08:00
for statement in ast.0.iter() {
if let Statement::Declaration(decl) = statement {
2018-02-27 03:01:05 -08:00
match decl {
FuncSig(signature) | FuncDecl(signature, _) => {
2018-05-13 15:54:15 -07:00
self.symbol_table.values.insert(
signature.name.clone(),
2018-05-15 23:48:36 -07:00
Symbol { name: signature.name.clone(), spec: SymbolSpec::Func }
2018-05-13 15:54:15 -07:00
);
},
TypeDecl(TypeSingletonName { name, ..}, TypeBody(variants)) => {
for var in variants {
match var {
Variant::UnitStruct(variant_name) => {
//TODO will have to make this a function to this type eventually
2018-05-15 23:48:36 -07:00
let spec = SymbolSpec::Custom(format!("{}", name));
self.symbol_table.values.insert(variant_name.clone(), Symbol { name: variant_name.clone(), spec });
},
e => return Err(format!("{:?} not supported in typing yet", e)),
}
}
2018-02-27 03:01:05 -08:00
},
_ => ()
}
}
}
Ok(())
2018-02-26 21:43:53 -08:00
}
pub fn debug_symbol_table(&self) -> String {
let mut output = format!("Symbol table\n");
for (sym, ty) in &self.symbol_table.values {
write!(output, "{} -> {:?}\n", sym, ty).unwrap();
2018-03-01 22:32:38 -08:00
}
2018-05-15 23:03:50 -07:00
write!(output, "\nBindings\n").unwrap();
for (sym, ty) in &self.bindings {
write!(output, "{} : {:?}\n", sym, ty).unwrap();
}
2018-03-01 22:32:38 -08:00
output
2018-02-26 21:43:53 -08:00
}
2018-05-15 21:53:50 -07:00
pub fn type_check_ast(&mut self, ast: &parsing::AST) -> TypeResult<String> {
2018-05-15 21:53:50 -07:00
let ref block = ast.0;
2018-05-17 00:36:51 -07:00
let mut infer = Infer::new();
let output = infer.infer_block(block)?;
Ok(format!("{:?}", output))
2018-05-15 21:53:50 -07:00
}
2018-02-26 21:43:53 -08:00
}
2018-05-17 00:36:51 -07:00
// this is the equivalent of the Haskell Infer monad
#[derive(Debug)]
struct Infer {
}
impl Infer {
fn new() -> Infer {
Infer { }
}
fn infer_block(&mut self, block: &Vec<parsing::Statement>) -> TypeResult<MonoType> {
Ok(MonoType::Const(TypeConst::Unit))
}
}
/*
2018-02-26 21:43:53 -08:00
impl TypeContext {
2018-05-15 22:08:37 -07:00
fn infer_block(&mut self, statements: &Vec<parsing::Statement>) -> TypeResult<Type> {
2018-05-15 21:53:50 -07:00
let mut ret_type = Type::Const(TConst::Unit);
for statement in statements {
2018-05-15 22:08:37 -07:00
ret_type = self.infer_statement(statement)?;
2018-02-21 02:31:28 -08:00
}
Ok(ret_type)
}
2018-05-15 21:53:50 -07:00
2018-05-15 22:08:37 -07:00
fn infer_statement(&mut self, statement: &parsing::Statement) -> TypeResult<Type> {
2018-02-21 02:31:28 -08:00
use self::parsing::Statement::*;
match statement {
2018-05-15 14:26:11 -07:00
ExpressionStatement(expr) => self.infer(expr),
Declaration(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 { name, 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 {
2018-05-15 14:26:11 -07:00
Expression(e, Some(anno)) => {
let anno_ty = anno.to_type()?;
2018-02-22 03:21:58 -08:00
let ty = self.infer_exprtype(&e)?;
self.unify(ty, anno_ty)
},
2018-05-15 14:26:11 -07:00
Expression(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 {
2018-05-15 14:26:11 -07:00
NatLiteral(_) => Ok(Const(Nat)),
FloatLiteral(_) => Ok(Const(Float)),
StringLiteral(_) => Ok(Const(StringT)),
BoolLiteral(_) => Ok(Const(Bool)),
BinExp(op, lhs, rhs) => { /* remember there are both the haskell convention talk and the write you a haskell ways to do this! */
match op.get_type()? {
2018-02-23 01:49:37 -08:00
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)
},
2018-02-26 18:23:10 -08:00
other => Err(format!("{:?} is not a binary function type", other))
2018-02-23 01:49:37 -08:00
}
2018-02-22 19:59:53 -08:00
},
2018-05-15 14:26:11 -07:00
PrefixExp(op, expr) => match op.get_type()? {
2018-02-26 02:21:21 -08:00
Func(box t1, box t2) => {
let expr_ty = self.infer(expr)?;
self.unify(t1, expr_ty)?;
Ok(t2)
},
2018-02-26 18:23:10 -08:00
other => Err(format!("{:?} is not a prefix op function type", other))
},
2018-05-15 14:26:11 -07:00
Value(name) => {
2018-02-26 18:23:10 -08:00
match self.bindings.get(name) {
Some(ty) => Ok(ty.clone()),
None => Err(format!("No binding found for variable: {}", name)),
}
2018-02-26 02:21:21 -08:00
},
2018-05-15 14:26:11 -07:00
Call { f, arguments } => {
2018-02-26 21:28:11 -08:00
let mut tf = self.infer(f)?;
for arg in arguments.iter() {
match tf {
Func(box t, box rest) => {
let t_arg = self.infer(arg)?;
self.unify(t, t_arg)?;
tf = rest;
},
other => return Err(format!("Function call failed to unify; last type: {:?}", other)),
}
}
Ok(tf)
},
2018-05-15 14:26:11 -07:00
TupleLiteral(expressions) => {
2018-03-03 11:55:20 -08:00
let mut types = vec![];
for expr in expressions {
types.push(self.infer(expr)?);
}
Ok(Sum(types))
},
2018-02-21 14:14:24 -08:00
_ => Err(format!("Type not yet implemented"))
2018-02-21 03:39:40 -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
}
*/
2018-02-21 02:31:28 -08:00