Skip to main content

typr_core/components/language/
var.rs

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