2020-12-24 16:06:16 +08:00
|
|
|
use std::collections::HashMap;
|
2020-12-26 11:45:57 +08:00
|
|
|
use std::rc::Rc;
|
2020-12-24 16:06:16 +08:00
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
|
2020-12-24 16:06:16 +08:00
|
|
|
pub struct PrimitiveId(usize);
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
|
2020-12-24 16:06:16 +08:00
|
|
|
pub struct ClassId(usize);
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
|
2020-12-24 16:06:16 +08:00
|
|
|
pub struct ParamId(usize);
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
|
2020-12-24 16:06:16 +08:00
|
|
|
pub struct VariableId(usize);
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
2020-12-24 16:06:16 +08:00
|
|
|
pub enum Type {
|
|
|
|
BotType,
|
|
|
|
SelfType,
|
|
|
|
PrimitiveType(PrimitiveId),
|
|
|
|
ClassType(ClassId),
|
|
|
|
VirtualClassType(ClassId),
|
2020-12-26 11:45:57 +08:00
|
|
|
ParametricType(ParamId, Vec<Rc<Type>>),
|
2020-12-24 16:06:16 +08:00
|
|
|
TypeVariable(VariableId),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct FnDef {
|
2020-12-28 11:06:32 +08:00
|
|
|
pub args: Rc<Type>,
|
|
|
|
pub result: Option<Rc<Type>>,
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct TypeDef<'a> {
|
|
|
|
pub name: &'a str,
|
|
|
|
pub fields: HashMap<&'a str, Type>,
|
|
|
|
pub methods: HashMap<&'a str, FnDef>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ClassDef<'a> {
|
|
|
|
pub base: TypeDef<'a>,
|
|
|
|
pub parents: Vec<ClassId>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ParametricDef<'a> {
|
|
|
|
pub base: TypeDef<'a>,
|
|
|
|
pub params: Vec<VariableId>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct VarDef<'a> {
|
|
|
|
pub name: &'a str,
|
2020-12-28 11:06:32 +08:00
|
|
|
pub bound: Vec<Rc<Type>>,
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
pub const TUPLE_TYPE: ParamId = ParamId(0);
|
|
|
|
pub const LIST_TYPE: ParamId = ParamId(1);
|
|
|
|
|
|
|
|
pub const BOOL_TYPE: PrimitiveId = PrimitiveId(0);
|
|
|
|
pub const INT32_TYPE: PrimitiveId = PrimitiveId(1);
|
|
|
|
|
2020-12-24 16:06:16 +08:00
|
|
|
pub struct GlobalContext<'a> {
|
|
|
|
primitive_defs: Vec<TypeDef<'a>>,
|
|
|
|
class_defs: Vec<ClassDef<'a>>,
|
|
|
|
parametric_defs: Vec<ParametricDef<'a>>,
|
|
|
|
var_defs: Vec<VarDef<'a>>,
|
|
|
|
sym_table: HashMap<&'a str, Type>,
|
2020-12-28 11:06:32 +08:00
|
|
|
fn_table: HashMap<&'a str, FnDef>,
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> GlobalContext<'a> {
|
|
|
|
pub fn new(primitives: Vec<TypeDef<'a>>) -> GlobalContext {
|
|
|
|
let mut sym_table = HashMap::new();
|
|
|
|
for (i, t) in primitives.iter().enumerate() {
|
|
|
|
sym_table.insert(t.name, Type::PrimitiveType(PrimitiveId(i)));
|
|
|
|
}
|
|
|
|
return GlobalContext {
|
|
|
|
primitive_defs: primitives,
|
|
|
|
class_defs: Vec::new(),
|
|
|
|
parametric_defs: Vec::new(),
|
|
|
|
var_defs: Vec::new(),
|
2020-12-28 11:06:32 +08:00
|
|
|
fn_table: HashMap::new(),
|
2020-12-24 16:06:16 +08:00
|
|
|
sym_table,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_class(&mut self, def: ClassDef<'a>) {
|
|
|
|
self.sym_table.insert(
|
|
|
|
def.base.name,
|
|
|
|
Type::ClassType(ClassId(self.class_defs.len())),
|
|
|
|
);
|
|
|
|
self.class_defs.push(def);
|
|
|
|
}
|
2020-12-28 11:06:32 +08:00
|
|
|
|
2020-12-24 16:06:16 +08:00
|
|
|
pub fn add_parametric(&mut self, def: ParametricDef<'a>) {
|
2020-12-26 11:45:57 +08:00
|
|
|
let params = def
|
|
|
|
.params
|
|
|
|
.iter()
|
2020-12-28 11:06:32 +08:00
|
|
|
.map(|&v| Rc::new(Type::TypeVariable(v)))
|
2020-12-26 11:45:57 +08:00
|
|
|
.collect();
|
2020-12-24 16:06:16 +08:00
|
|
|
self.sym_table.insert(
|
|
|
|
def.base.name,
|
|
|
|
Type::ParametricType(ParamId(self.parametric_defs.len()), params),
|
|
|
|
);
|
|
|
|
self.parametric_defs.push(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_variable(&mut self, def: VarDef<'a>) {
|
|
|
|
self.sym_table.insert(
|
|
|
|
def.name,
|
|
|
|
Type::TypeVariable(VariableId(self.var_defs.len())),
|
|
|
|
);
|
|
|
|
self.var_defs.push(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_variable_private(&mut self, def: VarDef<'a>) {
|
|
|
|
self.var_defs.push(def);
|
|
|
|
}
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
pub fn add_fn(&'a mut self, name: &'a str, def: FnDef) {
|
|
|
|
self.fn_table.insert(name, def);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_fn(&self, name: &str) -> Option<&FnDef> {
|
|
|
|
self.fn_table.get(name)
|
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_primitive_mut(&mut self, id: PrimitiveId) -> &mut TypeDef<'a> {
|
|
|
|
self.primitive_defs.get_mut(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_primitive(&self, id: PrimitiveId) -> &TypeDef {
|
|
|
|
self.primitive_defs.get(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_class_mut(&mut self, id: ClassId) -> &mut ClassDef<'a> {
|
|
|
|
self.class_defs.get_mut(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_class(&self, id: ClassId) -> &ClassDef {
|
|
|
|
self.class_defs.get(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_parametric_mut(&mut self, id: ParamId) -> &mut ParametricDef<'a> {
|
|
|
|
self.parametric_defs.get_mut(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_parametric(&self, id: ParamId) -> &ParametricDef {
|
|
|
|
self.parametric_defs.get(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_variable_mut(&mut self, id: VariableId) -> &mut VarDef<'a> {
|
|
|
|
self.var_defs.get_mut(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-26 11:45:57 +08:00
|
|
|
pub fn get_variable(&self, id: VariableId) -> &VarDef {
|
|
|
|
self.var_defs.get(id.0).unwrap()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_type(&self, name: &str) -> Option<Type> {
|
|
|
|
// TODO: change this to handle import
|
|
|
|
self.sym_table.get(name).map(|v| v.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Type {
|
2020-12-28 11:06:32 +08:00
|
|
|
pub fn subst(&self, map: &HashMap<VariableId, Rc<Type>>) -> Type {
|
2020-12-26 11:45:57 +08:00
|
|
|
match self {
|
2020-12-28 11:06:32 +08:00
|
|
|
Type::TypeVariable(id) => map.get(id).map(|v| v.as_ref()).unwrap_or(self).clone(),
|
2020-12-26 11:45:57 +08:00
|
|
|
Type::ParametricType(id, params) => Type::ParametricType(
|
|
|
|
*id,
|
|
|
|
params
|
|
|
|
.iter()
|
|
|
|
.map(|v| v.as_ref().subst(map).into())
|
|
|
|
.collect(),
|
|
|
|
),
|
|
|
|
_ => self.clone(),
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
pub fn inv_subst(&self, map: &[(Rc<Type>, Rc<Type>)]) -> Rc<Type> {
|
2020-12-24 16:06:16 +08:00
|
|
|
for (from, to) in map.iter() {
|
2020-12-28 11:06:32 +08:00
|
|
|
if self == from.as_ref() {
|
2020-12-26 11:45:57 +08:00
|
|
|
return to.clone();
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
match self {
|
2020-12-26 11:45:57 +08:00
|
|
|
Type::ParametricType(id, params) => Type::ParametricType(
|
|
|
|
*id,
|
|
|
|
params
|
|
|
|
.iter()
|
|
|
|
.map(|v| v.as_ref().inv_subst(map).into())
|
|
|
|
.collect(),
|
|
|
|
),
|
|
|
|
_ => self.clone(),
|
2020-12-28 11:06:32 +08:00
|
|
|
}.into()
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
|
2020-12-28 11:06:32 +08:00
|
|
|
pub fn get_subst(&self, ctx: &GlobalContext) -> HashMap<VariableId, Rc<Type>> {
|
2020-12-24 16:06:16 +08:00
|
|
|
match self {
|
|
|
|
Type::ParametricType(id, params) => {
|
2020-12-26 11:45:57 +08:00
|
|
|
let vars = &ctx.get_parametric(*id).params;
|
|
|
|
vars.iter()
|
|
|
|
.zip(params)
|
2020-12-28 11:06:32 +08:00
|
|
|
.map(|(v, p)| (*v, p.as_ref().clone().into()))
|
2020-12-26 11:45:57 +08:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
// if this proves to be slow, we can use option type
|
|
|
|
_ => HashMap::new(),
|
2020-12-24 16:06:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|