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;
|
2018-05-15 03:25:40 -07:00
|
|
|
//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
|
|
|
|
2018-05-10 21:41:28 -07:00
|
|
|
pub struct TypeContext {
|
2018-05-20 18:44:31 -07:00
|
|
|
environment: TypeEnvironment,
|
2018-05-14 09:46:25 -07:00
|
|
|
pub symbol_table: SymbolTable
|
2018-05-10 21:41:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//cf. p. 150 or so of Language Implementation Patterns
|
2018-05-14 15:01:37 -07:00
|
|
|
pub struct SymbolTable {
|
2018-05-13 15:17:25 -07:00
|
|
|
pub values: HashMap<Rc<String>, Symbol> //TODO this will eventually have real type information
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SymbolTable {
|
|
|
|
fn new() -> SymbolTable {
|
|
|
|
SymbolTable { values: HashMap::new() }
|
|
|
|
}
|
|
|
|
}
|
2018-05-10 21:41:28 -07:00
|
|
|
|
2018-05-13 15:42:10 -07:00
|
|
|
#[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 {
|
2018-05-17 01:06:52 -07:00
|
|
|
let mut map: HashMap<Rc<String>, MonoType> = HashMap::new();
|
|
|
|
for (name, monotype) in s.0.iter() {
|
|
|
|
if let None = self.0.get(name) {
|
|
|
|
map.insert(name.clone(), monotype.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let newsub = Substitution(map);
|
|
|
|
let new = self.1.apply_substitution(&newsub);
|
|
|
|
PolyType(self.0.clone(), new)
|
2018-05-17 00:48:48 -07:00
|
|
|
}
|
2018-05-17 00:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
struct Substitution(HashMap<Rc<String>, MonoType>);
|
|
|
|
|
2018-05-17 23:13:53 -07:00
|
|
|
impl Substitution {
|
|
|
|
fn new() -> Substitution {
|
|
|
|
Substitution(HashMap::new())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bind_variable(name: &Rc<String>, var: &MonoType) -> Substitution {
|
|
|
|
Substitution(hashmap! {
|
|
|
|
name.clone() => var.clone()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn merge(self, other: Substitution) -> Substitution {
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
for (name, ty) in self.0.into_iter() {
|
|
|
|
map.insert(name, ty);
|
|
|
|
}
|
|
|
|
for (name, ty) in other.0.into_iter() {
|
|
|
|
map.insert(name, ty);
|
|
|
|
}
|
|
|
|
Substitution(map)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-17 00:36:51 -07:00
|
|
|
|
2018-05-17 23:27:28 -07:00
|
|
|
#[derive(Debug, Default)]
|
2018-05-17 02:25:36 -07:00
|
|
|
struct TypeEnvironment {
|
|
|
|
map: HashMap<Rc<String>, PolyType>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeEnvironment {
|
|
|
|
fn apply_substitution(&self, s: &Substitution) -> TypeEnvironment {
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
for (name, polytype) in self.map.iter() {
|
|
|
|
map.insert(name.clone(), polytype.apply_substitution(s));
|
|
|
|
}
|
|
|
|
TypeEnvironment { map }
|
|
|
|
}
|
2018-05-19 01:57:03 -07:00
|
|
|
|
|
|
|
fn lookup(&self, name: &Rc<String>) -> Option<PolyType> {
|
|
|
|
self.map.get(name).map(|x| x.clone())
|
|
|
|
}
|
2018-05-17 02:25:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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-02-21 04:32:17 -08:00
|
|
|
}
|
|
|
|
|
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 */
|
2018-02-23 02:30:34 -08:00
|
|
|
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::*;
|
2018-02-23 02:30:34 -08:00
|
|
|
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),
|
2018-02-23 02:30:34 -08:00
|
|
|
"Int" => Const(Int),
|
|
|
|
"Float" => Const(Float),
|
|
|
|
"Bool" => Const(Bool),
|
|
|
|
"String" => Const(StringT),
|
2018-05-16 01:08:06 -07:00
|
|
|
*/
|
2018-02-23 02:30:34 -08:00
|
|
|
n => Const(Custom(n.to_string()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-24 17:37:23 -08:00
|
|
|
pub type TypeResult<T> = Result<T, String>;
|
2018-02-21 02:31:28 -08:00
|
|
|
|
|
|
|
impl TypeContext {
|
|
|
|
pub fn new() -> TypeContext {
|
2018-05-20 18:44:31 -07:00
|
|
|
TypeContext { environment: TypeEnvironment::default(), /*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<()> {
|
2018-05-13 15:42:10 -07:00
|
|
|
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() {
|
2018-05-13 15:42:10 -07:00
|
|
|
if let Statement::Declaration(decl) = statement {
|
2018-02-27 03:01:05 -08:00
|
|
|
match decl {
|
2018-05-13 15:42:10 -07:00
|
|
|
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
|
|
|
);
|
2018-05-13 15:42:10 -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 });
|
2018-05-13 15:42:10 -07:00
|
|
|
},
|
|
|
|
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 {
|
2018-05-13 15:42:10 -07:00
|
|
|
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-20 18:44:31 -07:00
|
|
|
write!(output, "\nType Env\n").unwrap();
|
|
|
|
for (sym, ty) in &self.environment.map {
|
2018-05-15 23:03:50 -07:00
|
|
|
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
|
|
|
|
2018-05-16 01:01:30 -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 23:21:23 -07:00
|
|
|
let mut infer = Infer::default();
|
2018-05-18 00:21:11 -07:00
|
|
|
let env = TypeEnvironment::default();
|
|
|
|
let output = infer.infer_block(block, &env);
|
2018-05-17 02:29:17 -07:00
|
|
|
match output {
|
|
|
|
Ok(s) => Ok(format!("{:?}", s)),
|
|
|
|
Err(s) => Err(format!("Error: {:?}", s))
|
|
|
|
}
|
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
|
2018-05-17 23:21:23 -07:00
|
|
|
#[derive(Debug, Default)]
|
2018-05-17 00:36:51 -07:00
|
|
|
struct Infer {
|
2018-05-17 23:21:23 -07:00
|
|
|
_idents: u32,
|
2018-05-17 00:36:51 -07:00
|
|
|
}
|
|
|
|
|
2018-05-17 02:29:17 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum InferError {
|
|
|
|
CannotUnify(MonoType, MonoType),
|
|
|
|
OccursCheckFailed(Rc<String>, MonoType),
|
2018-05-18 03:12:18 -07:00
|
|
|
UnknownIdentifier(Rc<String>),
|
|
|
|
Custom(String),
|
2018-05-17 02:29:17 -07:00
|
|
|
}
|
|
|
|
|
2018-05-18 01:43:51 -07:00
|
|
|
type InferResult<T> = Result<T, InferError>;
|
|
|
|
|
2018-05-17 00:36:51 -07:00
|
|
|
impl Infer {
|
2018-05-17 23:21:23 -07:00
|
|
|
fn fresh(&mut self) -> MonoType {
|
|
|
|
let i = self._idents;
|
|
|
|
self._idents += 1;
|
|
|
|
let name = Rc::new(format!("{}", ('a' as u8 + 1) as char));
|
|
|
|
MonoType::Var(name)
|
2018-05-17 00:36:51 -07:00
|
|
|
}
|
|
|
|
|
2018-05-18 01:43:51 -07:00
|
|
|
fn unify(&mut self, a: MonoType, b: MonoType) -> InferResult<Substitution> {
|
2018-05-17 23:13:53 -07:00
|
|
|
use self::InferError::*; use self::MonoType::*;
|
|
|
|
Ok(match (a, b) {
|
|
|
|
(Const(ref a), Const(ref b)) if a == b => Substitution::new(),
|
|
|
|
(Var(ref name), ref var) => Substitution::bind_variable(name, var),
|
|
|
|
(ref var, Var(ref name)) => Substitution::bind_variable(name, var),
|
|
|
|
(Function(box a1, box b1), Function(box a2, box b2)) => {
|
|
|
|
let s1 = self.unify(a1, a2)?;
|
|
|
|
let s2 = self.unify(b1.apply_substitution(&s1), b2.apply_substitution(&s1))?;
|
|
|
|
s1.merge(s2)
|
|
|
|
},
|
|
|
|
(a, b) => return Err(CannotUnify(a, b))
|
|
|
|
})
|
|
|
|
}
|
2018-05-17 00:36:51 -07:00
|
|
|
|
2018-05-18 01:43:51 -07:00
|
|
|
fn infer_block(&mut self, block: &Vec<parsing::Statement>, env: &TypeEnvironment) -> InferResult<MonoType> {
|
2018-05-18 00:21:11 -07:00
|
|
|
use self::parsing::Statement;
|
|
|
|
let mut ret = MonoType::Const(TypeConst::Unit);
|
|
|
|
for statement in block.iter() {
|
|
|
|
ret = match statement {
|
|
|
|
Statement::ExpressionStatement(expr) => {
|
|
|
|
let (sub, ty) = self.infer_expr(expr, env)?;
|
|
|
|
//TODO handle substitution monadically
|
|
|
|
|
|
|
|
ty
|
|
|
|
}
|
|
|
|
Statement::Declaration(decl) => MonoType::Const(TypeConst::Unit),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(ret)
|
|
|
|
}
|
|
|
|
|
2018-05-18 01:43:51 -07:00
|
|
|
fn infer_expr(&mut self, expr: &parsing::Expression, env: &TypeEnvironment) -> InferResult<(Substitution, MonoType)> {
|
|
|
|
use self::parsing::Expression;
|
|
|
|
match expr {
|
|
|
|
Expression(e, Some(anno)) => self.infer_annotated_expr(e, anno, env),
|
|
|
|
/*
|
|
|
|
let anno_ty = anno.to_type()?;
|
|
|
|
let ty = self.infer_exprtype(&e)?;
|
|
|
|
self.unify(ty, anno_ty)
|
|
|
|
},
|
|
|
|
*/
|
|
|
|
Expression(e, None) => self.infer_exprtype(e, env)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn infer_annotated_expr(&mut self, expr: &parsing::ExpressionType, anno: &parsing::TypeName, env: &TypeEnvironment) -> InferResult<(Substitution, MonoType)> {
|
2018-05-18 03:12:18 -07:00
|
|
|
Err(InferError::Custom(format!("exprtype not done: {:?}", expr)))
|
|
|
|
}
|
|
|
|
fn infer_exprtype(&mut self, expr: &parsing::ExpressionType, env: &TypeEnvironment) -> InferResult<(Substitution, MonoType)> {
|
|
|
|
use self::parsing::ExpressionType::*;
|
|
|
|
use self::TypeConst::*;
|
|
|
|
Ok(match expr {
|
|
|
|
NatLiteral(_) => (Substitution::new(), MonoType::Const(Nat)),
|
|
|
|
FloatLiteral(_) => (Substitution::new(), MonoType::Const(Float)),
|
|
|
|
StringLiteral(_) => (Substitution::new(), MonoType::Const(StringT)),
|
|
|
|
BoolLiteral(_) => (Substitution::new(), MonoType::Const(Bool)),
|
2018-05-19 01:57:03 -07:00
|
|
|
Value(name) => match env.lookup(name) {
|
|
|
|
Some(sigma) => {
|
|
|
|
let tau = self.instantiate(&sigma);
|
|
|
|
(Substitution::new(), tau)
|
|
|
|
},
|
|
|
|
None => return Err(InferError::UnknownIdentifier(name.clone())),
|
|
|
|
},
|
|
|
|
/*
|
|
|
|
PrefixExp(op, expr) => match op.get_type()? {
|
|
|
|
Func(box t1, box t2) => {
|
|
|
|
let expr_ty = self.infer(expr)?;
|
|
|
|
self.unify(t1, expr_ty)?;
|
|
|
|
Ok(t2)
|
|
|
|
},
|
|
|
|
other => Err(format!("{:?} is not a prefix op function type", other))
|
|
|
|
},
|
|
|
|
*/
|
2018-05-18 03:12:18 -07:00
|
|
|
/*
|
|
|
|
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()? {
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
},
|
|
|
|
*/
|
|
|
|
e => return Err(InferError::Custom(format!("Type inference for {:?} not done", e)))
|
|
|
|
})
|
2018-05-18 00:21:11 -07:00
|
|
|
}
|
2018-05-19 01:57:03 -07:00
|
|
|
fn instantiate(&mut self, sigma: &PolyType) -> MonoType {
|
|
|
|
let ref ty: MonoType = sigma.1;
|
|
|
|
let mut subst = Substitution::new();
|
|
|
|
|
|
|
|
for name in sigma.0.iter() {
|
|
|
|
let fresh_mvar = self.fresh();
|
|
|
|
let new = Substitution::bind_variable(name, &fresh_mvar);
|
|
|
|
subst = subst.merge(new);
|
|
|
|
}
|
|
|
|
ty.apply_substitution(&subst)
|
|
|
|
}
|
2018-05-18 00:21:11 -07:00
|
|
|
}
|
2018-05-17 00:36:51 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-05-16 01:01:30 -07:00
|
|
|
/*
|
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 {
|
2018-05-15 03:25:40 -07:00
|
|
|
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"))
|
|
|
|
}
|
2018-02-22 03:25:05 -08:00
|
|
|
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)) => {
|
2018-02-23 02:30:34 -08:00
|
|
|
let anno_ty = anno.to_type()?;
|
2018-02-22 03:21:58 -08:00
|
|
|
let ty = self.infer_exprtype(&e)?;
|
2018-02-21 04:32:17 -08:00
|
|
|
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! */
|
2018-02-24 17:37:23 -08:00
|
|
|
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-02-26 21:00:36 -08:00
|
|
|
},
|
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
|
|
|
}
|
|
|
|
}
|
2018-02-21 04:32:17 -08:00
|
|
|
fn unify(&mut self, t1: Type, t2: Type) -> TypeResult<Type> {
|
2018-02-22 03:25:05 -08:00
|
|
|
use self::Type::*;// use self::TConst::*;
|
2018-02-21 04:32:17 -08:00
|
|
|
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-05-16 01:01:30 -07:00
|
|
|
*/
|
2018-02-21 02:31:28 -08:00
|
|
|
|