diff --git a/Cargo.lock b/Cargo.lock index f16dee5060..7966077cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -474,6 +474,13 @@ dependencies = [ "rustpython-parser", ] +[[package]] +name = "nac3type" +version = "0.1.0" +dependencies = [ + "rustpython-parser", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" diff --git a/Cargo.toml b/Cargo.toml index 938324ad75..a7cd60f8ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,5 @@ members = [ "nac3core", "nac3standalone", "nac3embedded", + "nac3type", ] diff --git a/nac3type/Cargo.toml b/nac3type/Cargo.toml new file mode 100644 index 0000000000..eb548c321e --- /dev/null +++ b/nac3type/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "nac3type" +version = "0.1.0" +authors = ["M-Labs"] +edition = "2018" + +[dependencies] +rustpython-parser = { git = "https://github.com/RustPython/RustPython", branch = "master" } + + diff --git a/nac3type/src/lib.rs b/nac3type/src/lib.rs new file mode 100644 index 0000000000..fed80085ec --- /dev/null +++ b/nac3type/src/lib.rs @@ -0,0 +1,5 @@ +extern crate rustpython_parser; + + +mod types; + diff --git a/nac3type/src/types.rs b/nac3type/src/types.rs new file mode 100644 index 0000000000..35b21bb345 --- /dev/null +++ b/nac3type/src/types.rs @@ -0,0 +1,179 @@ +use std::collections::HashMap; + +#[derive(PartialEq, Eq, Copy, Clone)] +pub struct PrimitiveId(usize); + +#[derive(PartialEq, Eq, Copy, Clone)] +pub struct ClassId(usize); + +#[derive(PartialEq, Eq, Copy, Clone)] +pub struct ParamId(usize); + +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +pub struct VariableId(usize); + +#[derive(PartialEq, Eq, Clone)] +pub enum Type { + BotType, + SelfType, + PrimitiveType(PrimitiveId), + ClassType(ClassId), + VirtualClassType(ClassId), + ParametricType(ParamId, Vec), + TypeVariable(VariableId), +} + +pub struct FnDef { + pub args: Vec, + pub result: Option, +} + +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, +} + +pub struct ParametricDef<'a> { + pub base: TypeDef<'a>, + pub params: Vec, +} + +pub struct VarDef<'a> { + pub name: &'a str, + pub bound: Vec, +} + +pub struct GlobalContext<'a> { + primitive_defs: Vec>, + class_defs: Vec>, + parametric_defs: Vec>, + var_defs: Vec>, + sym_table: HashMap<&'a str, Type>, +} + +impl<'a> GlobalContext<'a> { + pub fn new(primitives: Vec>) -> 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(), + 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); + } + pub fn add_parametric(&mut self, def: ParametricDef<'a>) { + let params = def.params.iter().map(|&v| Type::TypeVariable(v)).collect(); + 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); + } + + pub fn get_primitive_mut(&mut self, id: PrimitiveId) -> Option<&mut TypeDef<'a>> { + self.primitive_defs.get_mut(id.0) + } + + pub fn get_primitive(&self, id: PrimitiveId) -> Option<&TypeDef> { + self.primitive_defs.get(id.0) + } + + pub fn get_class_mut(&mut self, id: ClassId) -> Option<&mut ClassDef<'a>> { + self.class_defs.get_mut(id.0) + } + + pub fn get_class(&self, id: ClassId) -> Option<&ClassDef> { + self.class_defs.get(id.0) + } + + pub fn get_parametric_mut(&mut self, id: ParamId) -> Option<&mut ParametricDef<'a>> { + self.parametric_defs.get_mut(id.0) + } + + pub fn get_parametric(&self, id: ParamId) -> Option<&ParametricDef> { + self.parametric_defs.get(id.0) + } + + pub fn get_variable_mut(&mut self, id: VariableId) -> Option<&mut VarDef<'a>> { + self.var_defs.get_mut(id.0) + } + + pub fn get_variable(&self, id: VariableId) -> Option<&VarDef> { + self.var_defs.get(id.0) + } + + pub fn get_type(&self, name: &str) -> Option { + // TODO: change this to handle import + self.sym_table.get(name).map(|v| v.clone()) + } +} + +impl Type { + pub fn subst(&self, map: &Option>) -> Type { + if let Some(m) = map { + match self { + Type::TypeVariable(id) => m.get(id).unwrap_or(self).clone(), + Type::ParametricType(id, params) => { + Type::ParametricType(*id, params.iter().map(|v| v.subst(map)).collect()) + } + _ => self.clone(), + } + } else { + self.clone() + } + } + + pub fn inv_subst(&self, map: &Vec<(Type, Type)>) -> Type { + for (from, to) in map.iter() { + if self == from { + return to.clone() + } + } + match self { + Type::ParametricType(id, params) => { + Type::ParametricType(*id, params.iter().map(|v| v.inv_subst(map)).collect()) + }, + _ => self.clone() + } + } + + pub fn get_subst(&self, ctx: &GlobalContext) -> Option> { + match self { + Type::ParametricType(id, params) => { + let vars = &ctx.get_parametric(*id).unwrap().params; + Some(vars.iter().zip(params).map(|(v, p)| (*v, p.clone())).collect()) + }, + _ => None + } + } +}