Skip to main content

typr_core/components/context/
mod.rs

1pub mod config;
2pub mod graph;
3pub mod vartype;
4
5use crate::components::context::config::Config;
6use crate::components::context::config::Environment;
7use crate::components::context::config::TargetLanguage;
8use crate::components::context::graph::Graph;
9use crate::components::context::unification_map::UnificationMap;
10use crate::components::context::vartype::VarType;
11use crate::components::language::var::Var;
12use crate::components::language::var_function::VarFunction;
13use crate::components::language::Lang;
14use crate::components::r#type::argument_type::ArgumentType;
15use crate::components::r#type::type_system::TypeSystem;
16use crate::components::r#type::Type;
17use crate::processes::type_checking::match_types_to_generic;
18use crate::processes::type_checking::type_comparison::reduce_type;
19use crate::processes::type_checking::unification_map;
20use crate::utils::builder;
21use crate::utils::standard_library::not_in_blacklist;
22use std::collections::HashSet;
23use std::iter::Rev;
24use std::ops::Add;
25use tap::Pipe;
26
27#[derive(Debug, Clone, PartialEq)]
28pub struct Context {
29    pub typing_context: VarType,
30    pub subtypes: Graph<Type>,
31    config: Config,
32}
33
34impl Default for Context {
35    fn default() -> Self {
36        let config = Config::default();
37        Context {
38            config: config.clone(),
39            typing_context: VarType::from_config(config),
40            subtypes: Graph::new(),
41        }
42    }
43}
44
45impl From<Vec<(Lang, Type)>> for Context {
46    fn from(val: Vec<(Lang, Type)>) -> Self {
47        let val2: Vec<(Var, Type)> = val
48            .iter()
49            .map(|(lan, typ)| (Var::from_language(lan.clone()).unwrap(), typ.clone()))
50            .collect();
51        Context {
52            typing_context: val2.into(),
53            ..Context::default()
54        }
55    }
56}
57
58impl Context {
59    pub fn new(types: Vec<(Var, Type)>) -> Context {
60        Context {
61            typing_context: types.into(),
62            ..Context::default()
63        }
64    }
65
66    pub fn empty() -> Self {
67        Context {
68            config: Config::default(),
69            typing_context: VarType::new(),
70            subtypes: Graph::new(),
71        }
72    }
73
74    pub fn set_config(self, config: Config) -> Self {
75        Self {
76            config: config,
77            ..self
78        }
79    }
80
81    pub fn set_as_module_context(self) -> Context {
82        Self {
83            config: self.config.set_as_module(),
84            ..self
85        }
86    }
87
88    /// Retourne un nouveau Context avec le Graph de sous-typage mis à jour
89    pub fn with_subtypes(self, subtypes: Graph<Type>) -> Self {
90        Self { subtypes, ..self }
91    }
92
93    pub fn get_members(&self) -> Vec<(Var, Type)> {
94        self.typing_context
95            .variables()
96            .chain(self.aliases())
97            .cloned()
98            .collect::<Vec<_>>()
99    }
100
101    pub fn print_hierarchy(&self) {
102        self.subtypes.print_hierarchy();
103    }
104
105    pub fn variable_exist(&self, var: Var) -> Option<Var> {
106        self.typing_context.variable_exist(var)
107    }
108
109    pub fn get_type_from_variable(&self, var: &Var) -> Result<Type, String> {
110        let res = self
111            .variables()
112            .flat_map(|(var2, typ)| {
113                let conditions = (var.name == var2.name)
114                    && (var.is_opaque == var2.is_opaque)
115                    && var.related_type.is_subtype(&var2.related_type, self).0;
116                if conditions {
117                    Some(typ.clone())
118                } else {
119                    None
120                }
121            })
122            .reduce(|acc, x| if x.is_subtype(&acc, self).0 { x } else { acc });
123        match res {
124            Some(typ) => Ok(typ),
125            _ => Err(format!(
126                "Didn't find {} in the context: {}",
127                var.get_name(),
128                self.display_typing_context()
129            )),
130        }
131    }
132
133    pub fn get_types_from_name(&self, name: &str) -> Vec<Type> {
134        self.variables()
135            .filter(|(var, _)| var.get_name() == name)
136            .map(|(_, typ)| typ.clone())
137            .collect()
138    }
139
140    pub fn get_type_from_aliases(&self, var: &Var) -> Option<Type> {
141        self.aliases()
142            .flat_map(|(var2, type_)| {
143                let conditions = (var.name == var2.name)
144                    && (var.is_opaque == var2.is_opaque)
145                    && var.related_type.is_subtype(&var2.related_type, self).0;
146                if conditions {
147                    Some(type_.clone())
148                } else {
149                    None
150                }
151            })
152            .next()
153    }
154
155    fn is_matching_alias(&self, var1: &Var, var2: &Var) -> bool {
156        var1.name == var2.name
157    }
158
159    pub fn get_matching_alias_signature(&self, var: &Var) -> Option<(Type, Vec<Type>)> {
160        self.aliases()
161            .find(|(var2, _)| self.is_matching_alias(var, var2))
162            .map(|(var2, target_type)| {
163                if var2.is_opaque() {
164                    (var2.clone().to_alias_type(), vec![])
165                } else {
166                    if let Type::Params(types, _) = var2.get_type() {
167                        (target_type.clone(), types.clone())
168                    } else {
169                        panic!("The related type is not Params([...])");
170                    }
171                }
172            })
173    }
174
175    pub fn variables(&self) -> Rev<std::vec::IntoIter<&(Var, Type)>> {
176        self.typing_context.variables()
177    }
178
179    pub fn aliases(&self) -> Rev<std::vec::IntoIter<&(Var, Type)>> {
180        self.typing_context.aliases()
181    }
182
183    pub fn push_var_type(self, lang: Var, typ: Type, context: &Context) -> Context {
184        let reduced_type = typ.reduce(context);
185        let types = reduced_type.extract_types();
186        let var_type = self
187            .typing_context
188            .clone()
189            .pipe(|vt| {
190                (reduced_type.is_interface() && lang.is_variable())
191                    .then(|| {
192                        vt.clone()
193                            .push_interface(lang.clone(), reduced_type, typ.clone(), context)
194                    })
195                    .unwrap_or(vt.push_var_type(&[(lang.clone(), typ.clone())]))
196            })
197            .push_types(&types);
198        let new_subtypes = self.subtypes.add_types(&types, context);
199        Context {
200            typing_context: var_type,
201            subtypes: new_subtypes,
202            ..self
203        }
204    }
205
206    pub fn replace_or_push_var_type(self, lang: Var, typ: Type, context: &Context) -> Context {
207        let types = typ.reduce(context).extract_types();
208        let var_type = self
209            .typing_context
210            .clone()
211            .replace_or_push_var_type(&[(lang.clone(), typ.clone())])
212            .push_types(&types);
213        let new_subtypes = self.subtypes.add_types(&types, context);
214        Context {
215            typing_context: var_type,
216            subtypes: new_subtypes,
217            ..self
218        }
219    }
220
221    // Remove variables from the context
222    // For removing added variables for evaluating a function's body
223    pub fn remove_vars(self, vars: &[Var]) -> Context {
224        Context {
225            typing_context: self.typing_context.remove_vars(vars),
226            ..self
227        }
228    }
229
230    pub fn push_types(self, types: &[Type]) -> Self {
231        Self {
232            typing_context: self.typing_context.push_types(types),
233            ..self
234        }
235    }
236
237    pub fn get_type_from_existing_variable(&self, var: Var) -> Type {
238        if let Type::UnknownFunction(_) = var.get_type() {
239            var.get_type()
240        } else {
241            self.typing_context
242                .variables()
243                .find(|(v, _)| var.match_with(v, self))
244                .map(|(_, ty)| ty)
245                // Return Any type instead of panicking if variable not found
246                .unwrap_or(&Type::Any(var.get_help_data()))
247                .clone()
248        }
249    }
250
251    pub fn get_true_variable(&self, var: &Var) -> Var {
252        let res = self
253            .typing_context
254            .variables()
255            .find(|(v, _)| var.match_with(v, self))
256            .map(|(v, _)| v);
257        match res {
258            Some(vari) => vari.clone(),
259            _ => {
260                // Return the variable with UnknownFunction type if it's a standard function
261                // Otherwise return with Any type to allow error collection
262                if self.is_an_untyped_function(&var.get_name()) {
263                    var.clone()
264                        .set_type(Type::UnknownFunction(var.get_help_data()))
265                } else {
266                    var.clone().set_type(Type::Any(var.get_help_data()))
267                }
268            }
269        }
270    }
271
272    fn is_a_standard_function(&self, name: &str) -> bool {
273        !self.typing_context.name_exists_outside_of_std(name)
274    }
275
276    pub fn is_an_untyped_function(&self, name: &str) -> bool {
277        self.is_a_standard_function(name)
278    }
279
280    pub fn get_class(&self, t: &Type) -> String {
281        self.typing_context.get_class(&t.reduce(self))
282    }
283
284    pub fn get_class_unquoted(&self, t: &Type) -> String {
285        self.typing_context.get_class_unquoted(t)
286    }
287
288    pub fn module_aliases(&self) -> Vec<(Var, Type)> {
289        self.variables()
290            .flat_map(|(_, typ)| typ.clone().to_module_type())
291            .flat_map(|module| module.get_aliases())
292            .collect()
293    }
294
295    pub fn get_type_anotations(&self) -> String {
296        self.aliases()
297            .chain(
298                [
299                    (Var::from_name("Integer"), builder::integer_type_default()),
300                    (
301                        Var::from_name("Character"),
302                        builder::character_type_default(),
303                    ),
304                    (Var::from_name("Number"), builder::number_type()),
305                    (Var::from_name("Boolean"), builder::boolean_type()),
306                ]
307                .iter(),
308            )
309            .cloned()
310            .chain(self.module_aliases())
311            .filter(|(_, typ)| typ.clone().to_module_type().is_err())
312            .map(|(var, typ)| (typ, var.get_name()))
313            .map(|(typ, name)| {
314                format!(
315                    "{} <- function(x) x |> struct(c('{}', {}, {}))",
316                    name,
317                    name,
318                    self.get_class(&typ),
319                    self.get_classes(&typ).unwrap()
320                )
321            })
322            .collect::<Vec<_>>()
323            .join("\n")
324    }
325
326    pub fn get_type_anotation(&self, t: &Type) -> String {
327        self.typing_context.get_type_anotation(t)
328    }
329
330    pub fn get_type_anotation_no_parentheses(&self, t: &Type) -> String {
331        self.typing_context.get_type_anotation_no_parentheses(t)
332    }
333
334    pub fn get_classes(&self, t: &Type) -> Option<String> {
335        let res = self
336            .subtypes
337            .get_supertypes(t, self)
338            .iter()
339            .filter(|typ| (*typ).clone().to_module_type().is_err())
340            .filter(|typ| !typ.is_empty())
341            .map(|typ| self.get_class(typ))
342            .collect::<Vec<_>>()
343            .join(", ");
344        if res == "" {
345            Some("'None'".to_string())
346        } else {
347            Some(res)
348        }
349    }
350
351    pub fn get_functions(&self, var1: Var) -> Vec<(Var, Type)> {
352        self.typing_context
353            .variables()
354            .filter(|(var2, typ)| {
355                let reduced_type1 = var1.get_type().reduce(self);
356                let reduced_type2 = var2.get_type().reduce(self);
357                var1.get_name() == var2.get_name()
358                    && typ.is_function()
359                    && reduced_type1.is_subtype(&reduced_type2, self).0
360            })
361            .cloned()
362            .collect()
363    }
364
365    pub fn get_all_generic_functions(&self) -> Vec<(Var, Type)> {
366        let res = self
367            .typing_context
368            .variables()
369            .filter(|(_, typ)| typ.is_function())
370            .filter(|(var, _)| not_in_blacklist(&var.get_name()))
371            .filter(|(var, _)| !var.get_type().is_any())
372            .collect::<HashSet<_>>();
373        res.iter()
374            .map(|(var, typ)| (var.clone().add_backticks_if_percent(), typ.clone()))
375            .collect()
376    }
377
378    pub fn get_first_matching_function(&self, var1: Var) -> Type {
379        let res = self.typing_context.variables().find(|(var2, typ)| {
380            let reduced_type1 = var1.get_type().reduce(self);
381            let reduced_type2 = var2.get_type().reduce(self);
382            var1.get_name() == var2.get_name()
383                && typ.is_function()
384                && (reduced_type1.is_subtype(&reduced_type2, self).0
385                    || reduced_type1.is_upperrank_of(&reduced_type2))
386        });
387        if res.is_none() {
388            self.typing_context
389                .standard_library()
390                .iter()
391                .find(|(var2, _)| var2.get_name() == var1.get_name())
392                .expect(&format!(
393                    "Can't find var {} in the context:\n {}",
394                    var1.to_string(),
395                    self.display_typing_context()
396                ))
397                .clone()
398        } else {
399            res.unwrap().clone()
400        }
401        .1
402    }
403
404    pub fn get_matching_typed_functions(&self, var1: Var) -> Vec<Type> {
405        self.typing_context
406            .variables()
407            .filter(|(var2, typ)| {
408                let reduced_type1 = var1.get_type().reduce(self);
409                let reduced_type2 = var2.get_type().reduce(self);
410                var1.get_name() == var2.get_name()
411                    && typ.is_function()
412                    && (reduced_type1.is_subtype(&reduced_type2, self).0
413                        || reduced_type1.is_upperrank_of(&reduced_type2))
414            })
415            .map(|(_, typ)| typ.clone())
416            .collect::<Vec<_>>()
417    }
418
419    pub fn get_matching_untyped_functions(&self, var: Var) -> Result<Vec<Type>, String> {
420        let name1 = var.get_name();
421        let std_lib = self.typing_context.standard_library();
422        let res = std_lib
423            .iter()
424            .find(|(var2, _)| var2.get_name() == name1)
425            .map(|(_, typ)| typ);
426        match res {
427            Some(val) => Ok(vec![val.clone()]),
428            _ => Err(format!(
429                "Can't find var {} in the context:\n {}",
430                var.to_string(),
431                self.display_typing_context()
432            )),
433        }
434    }
435
436    pub fn get_matching_functions(&self, var: Var) -> Result<Vec<Type>, String> {
437        let res = self.get_matching_typed_functions(var.clone());
438        if res.len() == 0 {
439            self.get_matching_untyped_functions(var)
440        } else {
441            Ok(res)
442        }
443    }
444
445    pub fn get_type_from_class(&self, class: &str) -> Type {
446        self.typing_context.get_type_from_class(class)
447    }
448
449    pub fn add_arg_types(&self, params: &[ArgumentType]) -> Context {
450        let param_types = params
451            .iter()
452            .map(|arg_typ| reduce_type(self, &arg_typ.get_type()).for_var())
453            .map(|typ| match typ.to_owned() {
454                Type::Function(typs, _, _) => {
455                    if typs.len() > 0 {
456                        typs[0].clone()
457                    } else {
458                        typ
459                    }
460                }
461                t => t,
462            })
463            .collect::<Vec<_>>();
464        params
465            .into_iter()
466            .zip(param_types.clone().into_iter())
467            .map(|(arg_typ, par_typ)| {
468                (
469                    Var::from_name(&arg_typ.get_argument_str())
470                        .set_type(reduce_type(self, &par_typ)),
471                    reduce_type(self, &arg_typ.get_type()),
472                )
473            })
474            .fold(self.clone(), |cont, (var, typ)| {
475                cont.clone().push_var_type(var, typ, &cont)
476            })
477    }
478
479    pub fn set_environment(&self, e: Environment) -> Context {
480        Context {
481            config: self.config.set_environment(e),
482            ..self.clone()
483        }
484    }
485
486    pub fn display_typing_context(&self) -> String {
487        let res = self
488            .variables()
489            .chain(self.aliases())
490            .map(|(var, typ)| format!("{} ==> {}", var.to_string(), typ.to_string()))
491            .collect::<Vec<_>>()
492            .join("\n");
493        format!("CONTEXT:\n{}", res)
494    }
495
496    pub fn error(&self, msg: String) -> String {
497        format!("{}{}", msg, self.display_typing_context())
498    }
499
500    pub fn push_alias(self, alias_name: String, typ: Type) -> Self {
501        Context {
502            typing_context: self.typing_context.push_alias(alias_name, typ),
503            ..self
504        }
505    }
506
507    pub fn push_alias2(self, alias_var: Var, typ: Type) -> Self {
508        Context {
509            typing_context: self.typing_context.push_alias2(alias_var, typ),
510            ..self
511        }
512    }
513
514    pub fn in_a_project(&self) -> bool {
515        self.config.environment == Environment::Project
516    }
517
518    pub fn get_unification_map(
519        &self,
520        entered_types: &[Type],
521        param_types: &[Type],
522    ) -> Option<UnificationMap> {
523        let res = entered_types
524            .iter()
525            .zip(param_types.iter())
526            .map(|(val_typ, par_typ)| match_types_to_generic(self, &val_typ.clone(), par_typ))
527            .collect::<Option<Vec<_>>>();
528
529        let val = res
530            .map(|vec| vec.iter().cloned().flatten().collect::<Vec<_>>())
531            .map(|vec| UnificationMap::new(vec));
532
533        val
534    }
535
536    fn s3_type_definition(&self, var: &Var, typ: &Type) -> String {
537        let first_part = format!("{} <- function(x) x |> ", var.get_name());
538        match typ {
539            Type::RClass(v, _) => format!(
540                "{} struct(c({}))",
541                first_part,
542                v.iter().cloned().collect::<Vec<_>>().join(", ")
543            ),
544            _ => {
545                let class = if typ.is_primitive() {
546                    format!("'{}'", var.get_name())
547                } else {
548                    self.get_class(typ)
549                };
550                format!("{} struct(c({}))", first_part, class)
551            }
552        }
553    }
554
555    fn get_primitive_type_definition(&self) -> Vec<String> {
556        let primitives = [
557            ("Integer", builder::integer_type_default()),
558            ("Character", builder::character_type_default()),
559            ("Number", builder::number_type()),
560            ("Boolean", builder::boolean_type()),
561        ];
562        let new_context = self.clone().push_types(
563            &primitives
564                .iter()
565                .map(|(_, typ)| typ)
566                .cloned()
567                .collect::<Vec<_>>(),
568        );
569        primitives
570            .iter()
571            .map(|(name, prim)| {
572                (
573                    name,
574                    new_context.get_classes(prim).unwrap(),
575                    new_context.get_class(prim),
576                )
577            })
578            .map(|(name, cls, cl)| {
579                format!("{} <- function(x) x |> struct(c({}, {}))", name, cls, cl)
580            })
581            .collect::<Vec<_>>()
582    }
583
584    pub fn get_related_functions(&self, typ: &Type, functions: &VarFunction) -> Vec<Lang> {
585        let names = self.typing_context.get_related_functions(typ);
586        functions.get_bodies(&names)
587    }
588
589    pub fn get_functions_from_type(&self, typ: &Type) -> Vec<(Var, Type)> {
590        self.variables()
591            .cloned()
592            .filter(|(var, typ2)| typ2.is_function() && &var.get_type() == typ)
593            .collect()
594    }
595
596    pub fn get_functions_from_name(&self, name: &str) -> Vec<(Var, Type)> {
597        self.variables()
598            .cloned()
599            .filter(|(var, typ2)| typ2.is_function() && &var.get_name() == name)
600            .collect()
601    }
602
603    pub fn get_type_definition(&self, _functions: &VarFunction) -> String {
604        match self.get_target_language() {
605            TargetLanguage::R => self
606                .typing_context
607                .aliases
608                .iter()
609                .map(|(var, typ)| self.s3_type_definition(var, typ))
610                .chain(self.get_primitive_type_definition().iter().cloned())
611                .collect::<Vec<_>>()
612                .join("\n"),
613            TargetLanguage::JS => {
614                todo!();
615            }
616        }
617    }
618
619    pub fn update_variable(self, var: Var) -> Self {
620        Self {
621            typing_context: self.typing_context.update_variable(var),
622            ..self
623        }
624    }
625
626    pub fn set_target_language(self, language: TargetLanguage) -> Self {
627        Self {
628            config: self.config.set_target_language(language),
629            typing_context: self.typing_context.source(language),
630            ..self
631        }
632    }
633
634    pub fn set_default_var_types(self) -> Self {
635        Self {
636            typing_context: self.typing_context.set_default_var_types(),
637            ..self
638        }
639    }
640
641    pub fn get_target_language(&self) -> TargetLanguage {
642        self.config.get_target_language()
643    }
644
645    pub fn set_new_aliase_signature(self, alias: &str, related_type: Type) -> Self {
646        let alias = Var::from_type(alias.parse::<Type>().unwrap()).unwrap();
647        self.clone().push_alias2(alias, related_type)
648    }
649
650    pub fn extract_module_as_vartype(&self, module_name: &str) -> Self {
651        let typ = self
652            .get_type_from_variable(&Var::from_name(module_name))
653            .expect("The module name was not found");
654        let empty_context = Context::default();
655        let new_context = match typ.clone() {
656            Type::Module(args, _) => {
657                args.iter()
658                    .rev()
659                    .map(|arg_type| {
660                        (
661                            Var::try_from(arg_type.0.clone()).unwrap(),
662                            arg_type.1.clone(),
663                        )
664                    }) //TODO: Differenciate between pushing variable and
665                    //aliases
666                    .fold(empty_context.clone(), |acc, (var, typ)| {
667                        acc.clone().push_var_type(var, typ, &acc)
668                    })
669            }
670            _ => panic!("{} is not a module", module_name),
671        };
672        new_context
673            .clone()
674            .push_var_type(Var::from_name(module_name), typ, &new_context)
675    }
676
677    pub fn get_vartype(&self) -> VarType {
678        self.clone().typing_context
679    }
680
681    pub fn get_environment(&self) -> Environment {
682        self.config.environment
683    }
684    pub fn extend_typing_context(self, var_types: VarType) -> Self {
685        Self {
686            typing_context: self.typing_context + var_types,
687            ..self
688        }
689    }
690}
691
692impl Add for Context {
693    type Output = Self;
694
695    fn add(self, other: Self) -> Self::Output {
696        Context {
697            typing_context: self.typing_context + other.typing_context,
698            subtypes: self.subtypes + other.subtypes,
699            config: self.config,
700        }
701    }
702}
703
704#[cfg(test)]
705mod tests {
706    use super::*;
707
708    #[test]
709    fn test_default_context1() {
710        let context = Context::default();
711        println!("{}", context.display_typing_context());
712        assert!(true)
713    }
714}