mamba/check/context/clss/
mod.rs

1use std::collections::{HashMap, HashSet};
2use std::convert::TryFrom;
3use std::fmt;
4use std::fmt::{Display, Formatter};
5use std::hash::{Hash, Hasher};
6
7use itertools::{EitherOrBoth, enumerate, Itertools};
8
9use crate::check::context::{Context, LookupClass};
10use crate::check::context::arg::FunctionArg;
11use crate::check::context::arg::generic::GenericFunctionArg;
12use crate::check::context::clss::generic::GenericClass;
13use crate::check::context::field::Field;
14use crate::check::context::field::generic::GenericField;
15use crate::check::context::function::Function;
16use crate::check::context::function::generic::GenericFunction;
17use crate::check::context::parent::generic::GenericParent;
18use crate::check::name::{Any, Empty, Name, Substitute};
19use crate::check::name::string_name::StringName;
20use crate::check::name::true_name::TrueName;
21use crate::check::result::{TypeErr, TypeResult};
22use crate::common::position::Position;
23
24pub const INT: &str = "Int";
25pub const FLOAT: &str = "Float";
26pub const STRING: &str = "Str";
27pub const BOOL: &str = "Bool";
28pub const ENUM: &str = "Enum";
29pub const COMPLEX: &str = "Complex";
30
31pub const COLLECTION: &str = "Collection";
32pub const RANGE: &str = "Range";
33pub const SLICE: &str = "Slice";
34pub const SET: &str = "Set";
35pub const LIST: &str = "List";
36pub const DICT: &str = "Dict";
37
38pub const TUPLE: &str = "Tuple";
39pub const CALLABLE: &str = "Callable";
40pub const UNION: &str = "Union";
41
42pub const ANY: &str = "Any";
43pub const NONE: &str = "None";
44pub const EXCEPTION: &str = "Exception";
45
46pub mod generic;
47pub mod python;
48
49/// Concrete type.
50///
51/// Has fields and functions defined within and from parents for easy access.
52///
53/// Parents are immediate parents.
54///
55/// Vector of fields signifies the fields of self, followed by fields of
56/// consecutive parents and their parents. The same goes for functions.
57#[derive(Debug, Clone, Eq)]
58pub struct Class {
59    pub is_py_type: bool,
60    pub name: StringName,
61    pub concrete: bool,
62    pub args: Vec<FunctionArg>,
63    pub fields: HashSet<Field>,
64    pub parents: HashSet<TrueName>,
65    pub functions: HashSet<Function>,
66}
67
68pub trait HasParent<T> {
69    /// Has name as parent.
70    ///
71    /// Does recursive search. Is true if any ancestor is equal to name.
72    fn has_parent(&self, name: T, ctx: &Context, pos: Position) -> TypeResult<bool>;
73}
74
75pub trait GetField<T> {
76    fn field(&self, name: &str, ctx: &Context, pos: Position) -> TypeResult<T>;
77}
78
79pub trait GetFun<T> {
80    fn fun(&self, name: &StringName, ctx: &Context, pos: Position) -> TypeResult<T>;
81}
82
83impl HasParent<&StringName> for Class {
84    fn has_parent(&self, other: &StringName, ctx: &Context, pos: Position) -> TypeResult<bool> {
85        if self.name == *other || other.name.as_str() == ANY {
86            return Ok(true);
87        } else if (self.name.name == TUPLE && (other.name == TUPLE || other.name == COLLECTION)) ||
88            (self.name.name == *other.name && self.name.generics.len() == other.generics.len()) {
89
90            // Contender! check generics
91            // Tuple check is necessary evil, no way to specify variable generics for tuples
92            let mut all_generic_super = true;
93            for (s_name, o_name) in self.name.generics.iter().zip(&other.generics) {
94                for s_name in &s_name.names {
95                    all_generic_super &= ctx.class(s_name, pos)?.has_parent(o_name, ctx, pos)?;
96                }
97            }
98            if all_generic_super { return Ok(all_generic_super); }
99        }
100
101        Ok(self
102            .parents
103            .iter()
104            .map(|p| ctx.class(p, pos)?.has_parent(other, ctx, pos))
105            .collect::<Result<Vec<bool>, _>>()?
106            .iter()
107            .any(|b| *b))
108    }
109}
110
111impl HasParent<&TrueName> for Class {
112    fn has_parent(&self, name: &TrueName, ctx: &Context, pos: Position) -> TypeResult<bool> {
113        self.has_parent(&name.variant, ctx, pos)
114    }
115}
116
117impl HasParent<&Name> for Class {
118    fn has_parent(&self, name: &Name, ctx: &Context, pos: Position) -> TypeResult<bool> {
119        if name.contains(&TrueName::from(&self.name)) || name == &Name::any() {
120            return Ok(true);
121        }
122
123        let names = name.as_direct();
124        let parent_names: Vec<StringName> = self.parents.iter().map(StringName::from).collect();
125        let parent_classes: Vec<Class> =
126            parent_names.iter().map(|name| ctx.class(name, pos)).collect::<Result<_, _>>()?;
127
128        for name in names {
129            let res = parent_classes
130                .iter()
131                .map(|pc| pc.has_parent(&name, ctx, pos))
132                .collect::<Result<Vec<bool>, _>>()?;
133            if res.iter().any(|a| *a) {
134                return Ok(true);
135            }
136        }
137
138        Ok(false)
139    }
140}
141
142impl LookupClass<&Name, HashSet<Class>> for Context {
143    fn class(&self, class_name: &Name, pos: Position) -> TypeResult<HashSet<Class>> {
144        if class_name.is_empty() {
145            let msg = format!("Tried to get class for {class_name}");
146            return Err(vec![TypeErr::new(pos, &msg)]);
147        }
148        class_name.names.iter().map(|name| self.class(name, pos)).collect::<TypeResult<_>>()
149    }
150}
151
152impl LookupClass<&TrueName, Class> for Context {
153    fn class(&self, class: &TrueName, pos: Position) -> TypeResult<Class> {
154        self.class(&StringName::from(class), pos)
155    }
156}
157
158impl LookupClass<&StringName, Class> for Context {
159    /// Look up union of GenericClass and substitute generics to yield set of classes.
160    ///
161    /// Substitutes all generics in the class when found.
162    fn class(&self, class: &StringName, pos: Position) -> TypeResult<Class> {
163        if let Some(generic_class) = self.classes.iter().find(|c| c.name.name == class.name) {
164            let mut generics = HashMap::new();
165            if class.name == TUPLE || class.name == COLLECTION {
166                // Tuple and collection exception, variable generic count
167                let mut generic_keys: Vec<Name> = vec![];
168                for (i, gen) in enumerate(&class.generics) {
169                    generic_keys.push(Name::from(format!("G{i}").as_str()));
170                    generics.insert(Name::from(format!("G{i}").as_str()), gen.clone());
171                }
172
173                let name = StringName::new(class.name.as_str(), &generic_keys);
174                let generic_class = GenericClass { name, ..generic_class.clone() };
175                let class = Class::try_from((&generic_class, &generics, pos));
176                return class;
177            }
178
179            let placeholders = generic_class.name.clone();
180
181            for name in placeholders.generics.iter().zip_longest(class.generics.iter()) {
182                match name {
183                    EitherOrBoth::Both(placeholder, name) => {
184                        generics.insert(placeholder.clone(), name.clone());
185                    }
186                    EitherOrBoth::Left(placeholder) => {
187                        let msg = format!("No argument for generic {placeholder} in {class}");
188                        return Err(vec![TypeErr::new(pos, &msg)]);
189                    }
190                    EitherOrBoth::Right(placeholder) => {
191                        let msg = format!("Gave unexpected generic {placeholder} to {class}");
192                        return Err(vec![TypeErr::new(pos, &msg)]);
193                    }
194                }
195            }
196
197            Class::try_from((generic_class, &generics, pos))
198        } else {
199            let msg = format!("Type '{class}' is undefined.");
200            Err(vec![TypeErr::new(pos, &msg)])
201        }
202    }
203}
204
205impl Hash for Class {
206    fn hash<H: Hasher>(&self, state: &mut H) {
207        self.name.hash(state)
208    }
209}
210
211impl PartialEq for Class {
212    fn eq(&self, other: &Self) -> bool {
213        self.name == other.name
214    }
215}
216
217impl Display for Class {
218    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
219        write!(f, "{}", self.name)
220    }
221}
222
223impl TryFrom<(&GenericClass, &HashMap<Name, Name>, Position)> for Class {
224    type Error = Vec<TypeErr>;
225
226    fn try_from(
227        (generic, generics, pos): (&GenericClass, &HashMap<Name, Name>, Position),
228    ) -> Result<Self, Self::Error> {
229        let try_arg = |a: &GenericFunctionArg| FunctionArg::try_from((a, generics, pos));
230        let try_field = |field: &GenericField| Field::try_from((field, generics, pos));
231        let try_function = |fun: &GenericFunction| Function::try_from((fun, generics, pos));
232        let try_parent = |parent: &GenericParent| TrueName::try_from((parent, generics, pos));
233
234        Ok(Class {
235            is_py_type: generic.is_py_type,
236            name: generic.name.substitute(generics, pos)?,
237            concrete: generic.concrete,
238            args: generic.args.iter().map(try_arg).collect::<Result<_, _>>()?,
239            parents: generic.parents.iter().map(try_parent).collect::<Result<_, _>>()?,
240            fields: generic.fields.iter().map(try_field).collect::<Result<_, _>>()?,
241            functions: generic.functions.iter().map(try_function).collect::<Result<_, _>>()?,
242        })
243    }
244}
245
246impl Class {
247    pub fn constructor(&self, without_self: bool) -> Function {
248        Function {
249            is_py_type: false,
250            name: self.name.clone(),
251            self_mutable: None,
252            pure: false,
253            arguments: if without_self && !self.args.is_empty() {
254                self.args.iter().skip(1).cloned().collect()
255            } else {
256                self.args.clone()
257            },
258            raises: Name::empty(),
259            in_class: None,
260            ret_ty: Name::from(&self.name),
261        }
262    }
263}
264
265impl GetField<Field> for Class {
266    fn field(&self, name: &str, ctx: &Context, pos: Position) -> TypeResult<Field> {
267        if let Some(field) = self.fields.iter().find(|f| f.name == name) {
268            return Ok(field.clone());
269        }
270
271        for parent in &self.parents {
272            if let Ok(ok) = ctx.class(parent, pos)?.field(name, ctx, pos) {
273                return Ok(ok);
274            }
275        }
276        Err(vec![TypeErr::new(pos, &format!("'{self}' does not define '{name}'"))])
277    }
278}
279
280impl GetFun<Function> for Class {
281    /// Get function of class.
282    ///
283    /// If class does not implement function, traverse parents until function
284    /// found.
285    fn fun(&self, name: &StringName, ctx: &Context, pos: Position) -> TypeResult<Function> {
286        if let Some(function) = self.functions.iter().find(|f| &f.name == name) {
287            return Ok(function.clone());
288        }
289
290        for parent in &self.parents {
291            if let Ok(function) = ctx.class(parent, pos)?.fun(name, ctx, pos) {
292                return Ok(function);
293            }
294        }
295        Err(vec![TypeErr::new(pos, &format!("'{self}' does not define '{name}'"))])
296    }
297}
298
299pub fn concrete_to_python(name: &str) -> String {
300    match name {
301        INT => String::from(python::INT_PRIMITIVE),
302        FLOAT => String::from(python::FLOAT_PRIMITIVE),
303        STRING => String::from(python::STRING_PRIMITIVE),
304        BOOL => String::from(python::BOOL_PRIMITIVE),
305        ENUM => String::from(python::ENUM_PRIMITIVE),
306        COMPLEX => String::from(python::COMPLEX_PRIMITIVE),
307
308        COLLECTION => String::from(python::COLLECTION),
309        RANGE => String::from(python::RANGE),
310        SLICE => String::from(python::SLICE),
311        SET => String::from(python::SET),
312        LIST => String::from(python::LIST),
313        TUPLE => String::from(python::TUPLE),
314        DICT => String::from(python::DICT),
315
316        CALLABLE => String::from(python::CALLABLE),
317        NONE => String::from(python::NONE),
318        EXCEPTION => String::from(python::EXCEPTION),
319        UNION => String::from(python::UNION),
320        ANY => String::from(python::ANY),
321
322        other => String::from(other),
323    }
324}