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