Skip to main content

typr_core/components/language/
var.rs

1#![allow(
2    dead_code,
3    unused_variables,
4    unused_imports,
5    unreachable_code,
6    unused_assignments
7)]
8use crate::components::context::Context;
9use crate::components::error_message::help_data::HelpData;
10use crate::components::error_message::locatable::Locatable;
11use crate::components::language::Lang;
12use crate::components::r#type::function_type::FunctionType;
13use crate::components::r#type::tchar::Tchar;
14use crate::components::r#type::type_system::TypeSystem;
15use crate::components::r#type::Type;
16use crate::processes::parsing::elements::is_pascal_case;
17use crate::processes::transpiling::translatable::RTranslatable;
18use crate::processes::type_checking::typing;
19use crate::utils::builder;
20use serde::{Deserialize, Serialize};
21use std::fmt;
22
23type Name = String;
24type IsPackageOpaque = bool;
25
26#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize, Eq, Hash)]
27pub enum Permission {
28    Private,
29    Public,
30}
31
32impl fmt::Display for Permission {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            Permission::Private => write!(f, "private"),
36            Permission::Public => write!(f, "public"),
37        }
38    }
39}
40
41impl From<Permission> for bool {
42    fn from(val: Permission) -> Self {
43        matches!(val, Permission::Public)
44    }
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct Var {
49    pub name: Name,
50    pub is_opaque: IsPackageOpaque,
51    pub related_type: Type,
52    pub help_data: HelpData,
53}
54
55impl PartialEq for Var {
56    fn eq(&self, other: &Self) -> bool {
57        self.name == other.name
58            && self.is_opaque == other.is_opaque
59            && self.related_type == other.related_type
60    }
61}
62
63impl Eq for Var {}
64
65impl std::hash::Hash for Var {
66    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
67        self.name.hash(state);
68        self.is_opaque.hash(state);
69        self.related_type.hash(state);
70    }
71}
72
73impl Locatable for Var {
74    fn get_help_data(&self) -> HelpData {
75        self.help_data.clone()
76    }
77}
78
79impl Var {
80    pub fn set_type_from_params(self, params: &[Lang], context: &Context) -> Self {
81        let typ = if !params.is_empty() {
82            typing(context, &params[0]).value
83        } else {
84            Default::default()
85        };
86        self.set_type(typ)
87    }
88
89    pub fn add_backticks_if_percent(self) -> Self {
90        let s = self.get_name();
91        let res = if s.starts_with('%') && s.ends_with('%') {
92            format!("`{}`", s)
93        } else {
94            s.to_string()
95        };
96        self.set_name(&res)
97    }
98
99    pub fn alias(name: &str, params: &[Type]) -> Self {
100        Var::from(name).set_type(Type::Params(params.to_vec(), HelpData::default()))
101    }
102
103    pub fn set_var_related_type(&self, types: &[Type], context: &Context) -> Var {
104        if let Some(first_arg) = types.first() {
105            self.clone().set_type(first_arg.clone())
106        } else {
107            self.clone()
108        }
109    }
110
111    fn keep_minimal(liste: Vec<Type>, context: &Context) -> Option<Type> {
112        let mut mins: Vec<Type> = Vec::new();
113
114        for candidat in liste {
115            let mut keep_candidat = true;
116            let mut indices_to_delete = Vec::new();
117
118            for (i, existant) in mins.iter().enumerate() {
119                if candidat.is_subtype(existant, context).0 {
120                    indices_to_delete.push(i);
121                } else if existant.is_subtype(&candidat, context).0 {
122                    keep_candidat = false;
123                    break;
124                }
125            }
126
127            if keep_candidat {
128                for &i in indices_to_delete.iter().rev() {
129                    mins.remove(i);
130                }
131                mins.push(candidat);
132            }
133        }
134        // get smallest type
135        if mins.iter().any(|x| !x.is_interface()) {
136            mins.iter().find(|x| !x.is_interface()).cloned()
137        } else {
138            mins.first().cloned()
139        }
140    }
141
142    pub fn get_functions_from_name(&self, context: &Context) -> Vec<FunctionType> {
143        context
144            .get_functions_from_name(&self.get_name())
145            .iter()
146            .flat_map(|(_, typ)| typ.clone().to_function_type())
147            .collect()
148    }
149
150    pub fn from_language(l: Lang) -> Option<Var> {
151        match l {
152            Lang::Variable {
153                name,
154                is_opaque: muta,
155                related_type: typ,
156                help_data: h,
157            } => Some(Var {
158                name,
159                is_opaque: muta,
160                related_type: typ,
161                help_data: h,
162            }),
163            _ => None,
164        }
165    }
166
167    pub fn from_type(t: Type) -> Option<Var> {
168        match t {
169            Type::Alias(name, concret_types, opacity, h) => {
170                let var = Var::from_name(&name)
171                    .set_type(Type::Params(
172                        concret_types.to_vec(),
173                        concret_types.clone().into(),
174                    ))
175                    .set_help_data(h)
176                    .set_opacity(opacity);
177                Some(var)
178            }
179            Type::Char(val, h) => {
180                let var = Var::from_name(&val.get_val()).set_help_data(h);
181                Some(var)
182            }
183            _ => None,
184        }
185    }
186
187    pub fn from_name(name: &str) -> Self {
188        Var {
189            name: name.to_string(),
190            is_opaque: false,
191            related_type: builder::empty_type(),
192            help_data: HelpData::default(),
193        }
194    }
195
196    pub fn to_language(self) -> Lang {
197        Lang::Variable {
198            name: self.name,
199            is_opaque: self.is_opaque,
200            related_type: self.related_type,
201            help_data: self.help_data,
202        }
203    }
204
205    pub fn set_name(self, s: &str) -> Var {
206        Var {
207            name: s.to_string(),
208            is_opaque: self.is_opaque,
209            related_type: self.related_type,
210            help_data: self.help_data,
211        }
212    }
213
214    pub fn set_type(self, typ: Type) -> Var {
215        let typ = match typ {
216            Type::Function(params, _, h) => {
217                if !params.is_empty() {
218                    params[0].get_type()
219                } else {
220                    Type::Any(h)
221                }
222            }
223            _ => typ,
224        };
225        Var {
226            name: self.name,
227            is_opaque: self.is_opaque,
228            related_type: typ,
229            help_data: self.help_data,
230        }
231    }
232
233    pub fn set_type_raw(self, typ: Type) -> Var {
234        Var {
235            name: self.name,
236            is_opaque: self.is_opaque,
237            related_type: typ,
238            help_data: self.help_data,
239        }
240    }
241
242    pub fn set_opacity(self, opa: bool) -> Var {
243        Var {
244            name: self.name,
245            is_opaque: opa,
246            related_type: self.related_type,
247            help_data: self.help_data,
248        }
249    }
250
251    pub fn get_name(&self) -> String {
252        self.name.to_string()
253    }
254
255    pub fn get_type(&self) -> Type {
256        self.related_type.clone()
257    }
258
259    pub fn get_help_data(&self) -> HelpData {
260        self.help_data.clone()
261    }
262
263    pub fn match_with(&self, var: &Var, context: &Context) -> bool {
264        (self.get_name() == var.get_name())
265            && self.get_type().is_subtype(&var.get_type(), context).0
266    }
267
268    pub fn set_help_data(self, h: HelpData) -> Var {
269        Var {
270            name: self.name,
271            is_opaque: self.is_opaque,
272            related_type: self.related_type,
273            help_data: h,
274        }
275    }
276
277    pub fn is_imported(&self) -> bool {
278        self.is_variable() && self.is_opaque
279    }
280
281    pub fn is_alias(&self) -> bool {
282        matches!(self.get_type(), Type::Params(_, _))
283    }
284
285    pub fn is_variable(&self) -> bool {
286        !self.is_alias()
287    }
288
289    pub fn is_opaque(&self) -> bool {
290        self.is_alias() && self.is_opaque
291    }
292
293    pub fn get_opacity(&self) -> bool {
294        self.is_opaque
295    }
296
297    pub fn to_alias_type(self) -> Type {
298        Type::Alias(
299            self.get_name(),
300            vec![],
301            self.get_opacity(),
302            self.get_help_data(),
303        )
304    }
305
306    pub fn to_alias_lang(self) -> Lang {
307        Lang::Alias {
308            identifier: Box::new(self.clone().to_language()),
309            parameters: vec![],
310            target_type: builder::unknown_function_type(),
311            is_public: false,
312            help_data: self.get_help_data(),
313        }
314    }
315
316    pub fn to_let(self) -> Lang {
317        Lang::Let {
318            variable: Box::new(self.clone().to_language()),
319            r#type: builder::unknown_function_type(),
320            expression: Box::default(),
321            is_public: false,
322            is_testable: false,
323            is_export: false,
324            help_data: self.get_help_data(),
325        }
326    }
327
328    pub fn contains(&self, s: &str) -> bool {
329        self.get_name().contains(s)
330    }
331
332    pub fn replace(self, old: &str, new: &str) -> Self {
333        let res = self.get_name().replace(old, new);
334        self.set_name(&res)
335    }
336
337    pub fn display_type(self, cont: &Context) -> Self {
338        if !self.get_name().contains(".") {
339            let type_str = match self.get_type() {
340                Type::Empty(_) | Type::Any(_) => "".to_string(),
341                ty => ".".to_string() + &cont.get_class(&ty).replace("'", ""),
342            };
343            let new_name = if self.contains("`") {
344                "`".to_string() + &self.get_name().replace("`", "") + &type_str + "`"
345            } else {
346                self.get_name() + &type_str
347            };
348            self.set_name(&new_name)
349        } else {
350            self
351        }
352    }
353
354    pub fn get_digit(&self, s: &str) -> i8 {
355        self.get_name()[s.len()..].parse::<i8>().unwrap()
356    }
357
358    pub fn add_digit(self, d: i8) -> Self {
359        self.clone().set_name(&(self.get_name() + &d.to_string()))
360    }
361
362    pub fn exist(&self, context: &Context) -> Option<Self> {
363        context.variable_exist(self.clone())
364    }
365}
366
367impl fmt::Display for Var {
368    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369        write!(f, "{}<{}>", self.name, self.related_type)
370    }
371}
372
373impl Default for Var {
374    fn default() -> Self {
375        Var {
376            name: "".to_string(),
377            is_opaque: false,
378            related_type: Type::Empty(HelpData::default()),
379            help_data: HelpData::default(),
380        }
381    }
382}
383
384impl RTranslatable<String> for Var {
385    fn to_r(&self, _: &Context) -> String {
386        self.name.to_string()
387    }
388}
389
390impl TryFrom<Lang> for Var {
391    type Error = ();
392
393    fn try_from(value: Lang) -> Result<Self, Self::Error> {
394        match value {
395            Lang::Variable {
396                name,
397                is_opaque: muta,
398                related_type: typ,
399                help_data: h,
400            } => Ok(Var {
401                name,
402                is_opaque: muta,
403                related_type: typ,
404                help_data: h,
405            }),
406            _ => Err(()),
407        }
408    }
409}
410
411impl TryFrom<Box<Lang>> for Var {
412    type Error = ();
413
414    fn try_from(value: Box<Lang>) -> Result<Self, Self::Error> {
415        Var::try_from((*value).clone())
416    }
417}
418
419impl TryFrom<&Box<Lang>> for Var {
420    type Error = ();
421
422    fn try_from(value: &Box<Lang>) -> Result<Self, Self::Error> {
423        Var::try_from((*value).clone())
424    }
425}
426
427impl From<&str> for Var {
428    fn from(val: &str) -> Self {
429        Var {
430            name: val.to_string(),
431            is_opaque: false,
432            related_type: Type::Empty(HelpData::default()),
433            help_data: HelpData::default(),
434        }
435    }
436}
437
438impl TryFrom<Type> for Var {
439    type Error = String;
440
441    fn try_from(value: Type) -> Result<Self, Self::Error> {
442        match value {
443            Type::Char(tchar, h) => match tchar {
444                Tchar::Val(name) => {
445                    let var = if is_pascal_case(&name) {
446                        Var::from_name(&name)
447                            .set_help_data(h)
448                            .set_type(builder::params_type())
449                    } else {
450                        Var::from_name(&name).set_help_data(h)
451                    };
452                    Ok(var)
453                }
454                _ => todo!(),
455            },
456            _ => Err("From type to Var, not possible".to_string()),
457        }
458    }
459}