Skip to main content

typr_core/processes/transpiling/
mod.rs

1pub mod translatable;
2
3use crate::components::context::config::Environment;
4use crate::components::context::Context;
5use crate::components::error_message::help_data::HelpData;
6use crate::components::language::argument_value::ArgumentValue;
7use crate::components::language::format_backtick;
8use crate::components::language::function_lang::Function;
9use crate::components::language::operators::Op;
10use crate::components::language::set_related_type_if_variable;
11use crate::components::language::var::Var;
12use crate::components::language::Lang;
13use crate::components::language::ModulePosition;
14use crate::components::r#type::argument_type::ArgumentType;
15use crate::components::r#type::array_type::ArrayType;
16use crate::components::r#type::function_type::FunctionType;
17use crate::components::r#type::vector_type::VecType;
18use crate::components::r#type::Type;
19use crate::processes::transpiling::translatable::Translatable;
20use crate::processes::type_checking::flatten_operator_union;
21use crate::processes::type_checking::type_comparison::reduce_type;
22use crate::processes::type_checking::typing;
23use translatable::RTranslatable;
24
25#[cfg(not(feature = "wasm"))]
26use std::fs::File;
27#[cfg(not(feature = "wasm"))]
28use std::io::Write;
29#[cfg(not(feature = "wasm"))]
30use std::path::PathBuf;
31
32use std::cell::RefCell;
33use std::collections::HashMap;
34
35// Thread-local storage for generated files (used in WASM mode)
36thread_local! {
37    static GENERATED_FILES: RefCell<HashMap<String, String>> = RefCell::new(HashMap::new());
38}
39
40/// Register a generated file (used for WASM mode to capture file outputs)
41pub fn register_generated_file(path: &str, content: &str) {
42    GENERATED_FILES.with(|files| {
43        files
44            .borrow_mut()
45            .insert(path.to_string(), content.to_string());
46    });
47}
48
49/// Get all generated files
50pub fn get_generated_files() -> HashMap<String, String> {
51    GENERATED_FILES.with(|files| files.borrow().clone())
52}
53
54/// Clear all generated files
55pub fn clear_generated_files() {
56    GENERATED_FILES.with(|files| {
57        files.borrow_mut().clear();
58    });
59}
60
61/// Write a file - in native mode writes to filesystem, in WASM mode stores in memory
62#[cfg(not(feature = "wasm"))]
63fn write_output_file(path: &str, content: &str) -> Result<(), String> {
64    use std::fs;
65
66    // Also register in memory for consistency
67    register_generated_file(path, content);
68
69    let path_buf = PathBuf::from(path);
70    if let Some(parent) = path_buf.parent() {
71        fs::create_dir_all(parent).map_err(|e| e.to_string())?;
72    }
73    let mut file = File::create(&path_buf).map_err(|e| e.to_string())?;
74    file.write_all(content.as_bytes())
75        .map_err(|e| e.to_string())?;
76    Ok(())
77}
78
79#[cfg(feature = "wasm")]
80fn write_output_file(path: &str, content: &str) -> Result<(), String> {
81    register_generated_file(path, content);
82    Ok(())
83}
84
85pub trait ToSome {
86    fn to_some(self) -> Option<Self>
87    where
88        Self: Sized;
89}
90
91impl<T: Sized> ToSome for T {
92    fn to_some(self) -> Option<Self> {
93        Some(self)
94    }
95}
96
97trait AndIf {
98    fn and_if<F>(self, condition: F) -> Option<Self>
99    where
100        F: Fn(Self) -> bool,
101        Self: Sized;
102}
103
104impl<T: Clone> AndIf for T {
105    fn and_if<F>(self, condition: F) -> Option<Self>
106    where
107        F: Fn(Self) -> bool,
108    {
109        if condition(self.clone()) {
110            Some(self)
111        } else {
112            None
113        }
114    }
115}
116
117const JS_HEADER: &str = "";
118
119fn to_pattern_match_statement(
120    exp: Lang,
121    branches: &[(Lang, Box<Lang>)],
122    context: &Context,
123) -> String {
124    let match_var = "match_val__";
125    let res = branches
126        .iter()
127        .enumerate()
128        .map(|(id, (pattern, body))| {
129            let (cond, bindings) = pattern_to_condition(pattern, match_var, context);
130            let body_str = body.to_r(context).0;
131            let body_with_bindings = if bindings.is_empty() {
132                body_str
133            } else {
134                format!("{}\n{}", bindings, body_str)
135            };
136            if cond == "TRUE" {
137                // wildcard pattern: always matches
138                if id == 0 {
139                    format!("{{\n{}\n}}", body_with_bindings)
140                } else {
141                    format!("else {{\n{}\n}}", body_with_bindings)
142                }
143            } else if id == 0 {
144                format!("if ({}) {{\n{}\n}}", cond, body_with_bindings)
145            } else {
146                format!("else if ({}) {{\n{}\n}}", cond, body_with_bindings)
147            }
148        })
149        .collect::<Vec<_>>()
150        .join(" ");
151    format!("{{\n{} <- {}\n{}\n}}", match_var, exp.to_r(context).0, res)
152}
153
154/// Map a Type to its corresponding R type-check function name.
155fn type_to_r_check(typ: &Type) -> Option<&'static str> {
156    match typ {
157        Type::Integer(_, _) => Some("is.integer"),
158        Type::Boolean(_, _) => Some("is.logical"),
159        Type::Number(_, _) => Some("is.numeric"),
160        Type::Char(_, _) => Some("is.character"),
161        Type::Null(_) => Some("is.null"),
162        _ => None,
163    }
164}
165
166fn pattern_to_condition(pattern: &Lang, match_var: &str, _context: &Context) -> (String, String) {
167    match pattern {
168        // Tag with a binding variable: .Some(a)
169        Lang::Tag {
170            name, value: inner, ..
171        } => {
172            let cond = format!("{}[[1]] == '{}'", match_var, name);
173            match inner.as_ref() {
174                Lang::Variable { name: var_name, .. } => {
175                    let binding = format!("{} <- {}[[\"body\"]]", var_name, match_var);
176                    (cond, binding)
177                }
178                Lang::Empty(_) => (cond, String::new()),
179                _ => (cond, String::new()),
180            }
181        }
182        // Type pattern: x as int
183        Lang::TypePattern {
184            variable_name: var_name,
185            matched_type: typ,
186            ..
187        } => {
188            let check_fn = type_to_r_check(typ).unwrap_or("is.logical");
189            let cond = format!("{}({})", check_fn, match_var);
190            let binding = format!("{} <- {}", var_name, match_var);
191            (cond, binding)
192        }
193        // Tuple pattern: :{a, b, c}
194        Lang::Tuple {
195            value: elements, ..
196        } => {
197            let cond = format!(
198                "inherits({}, 'Tuple') && length({}) == {}",
199                match_var,
200                match_var,
201                elements.len()
202            );
203            let bindings: Vec<String> = elements
204                .iter()
205                .enumerate()
206                .filter_map(|(i, elem)| {
207                    if let Lang::Variable { name: var_name, .. } = elem {
208                        if var_name == "_" {
209                            None
210                        } else {
211                            Some(format!("{} <- {}[[{}]]", var_name, match_var, i + 1))
212                        }
213                    } else {
214                        None
215                    }
216                })
217                .collect();
218            (cond, bindings.join("\n"))
219        }
220        // List/record pattern: :{nom: n, age: a}
221        Lang::List { value: fields, .. } => {
222            let conditions: Vec<String> = fields
223                .iter()
224                .map(|arg_val: &ArgumentValue| {
225                    format!("!is.null({}[[\"{}\"]])", match_var, arg_val.get_argument())
226                })
227                .collect();
228            let cond = if conditions.is_empty() {
229                "is.list(".to_string() + match_var + ")"
230            } else {
231                format!("is.list({}) && {}", match_var, conditions.join(" && "))
232            };
233            let bindings: Vec<String> = fields
234                .iter()
235                .filter_map(|arg_val| {
236                    if let Lang::Variable { name: var_name, .. } = &arg_val.get_value() {
237                        Some(format!(
238                            "{} <- {}[[\"{}\"]]",
239                            var_name,
240                            match_var,
241                            arg_val.get_argument()
242                        ))
243                    } else {
244                        None
245                    }
246                })
247                .collect();
248            (cond, bindings.join("\n"))
249        }
250        // DataFrame pattern: data__frame(col1 = x, col2 = y)
251        Lang::DataFrame { value: fields, .. } => {
252            let conditions: Vec<String> = fields
253                .iter()
254                .map(|arg_val: &ArgumentValue| {
255                    format!("!is.null({}[[\"{}\"]])", match_var, arg_val.get_argument())
256                })
257                .collect();
258            let cond = if conditions.is_empty() {
259                "is.data.frame(".to_string() + match_var + ")"
260            } else {
261                format!(
262                    "is.data.frame({}) && {}",
263                    match_var,
264                    conditions.join(" && ")
265                )
266            };
267            let bindings: Vec<String> = fields
268                .iter()
269                .filter_map(|arg_val| {
270                    if let Lang::Variable { name: var_name, .. } = &arg_val.get_value() {
271                        Some(format!(
272                            "{} <- {}[[\"{}\"]]",
273                            var_name,
274                            match_var,
275                            arg_val.get_argument()
276                        ))
277                    } else {
278                        None
279                    }
280                })
281                .collect();
282            (cond, bindings.join("\n"))
283        }
284        // Wildcard: _
285        Lang::Variable { name, .. } if name == "_" => ("TRUE".to_string(), String::new()),
286        // Other variable: bind the whole value
287        Lang::Variable { name, .. } => {
288            let binding = format!("{} <- {}", name, match_var);
289            ("TRUE".to_string(), binding)
290        }
291        _ => ("TRUE".to_string(), String::new()),
292    }
293}
294
295impl RTranslatable<(String, Context)> for Lang {
296    fn to_r(&self, cont: &Context) -> (String, Context) {
297        let result = match self {
298            Lang::Bool { value: b, .. } => {
299                let (typ, _, _) = typing(cont, self).to_tuple();
300                let anotation = cont.get_type_anotation(&typ);
301                (
302                    format!("{} |> {}", b.to_string().to_uppercase(), anotation),
303                    cont.clone(),
304                )
305            }
306            Lang::Number { value: n, .. } => {
307                let (typ, _, _) = typing(cont, self).to_tuple();
308                let anotation = cont.get_type_anotation(&typ);
309                (format!("{} |> {}", n, anotation), cont.clone())
310            }
311            Lang::Integer { value: i, .. } => {
312                let (typ, _, _) = typing(cont, self).to_tuple();
313                let anotation = cont.get_type_anotation(&typ);
314                (format!("{}L |> {}", i, anotation), cont.clone())
315            }
316            Lang::Char { value: s, .. } => {
317                let (typ, _, _) = typing(cont, self).to_tuple();
318                let anotation = cont.get_type_anotation(&typ);
319                (format!("'{}' |> {}", s, anotation), cont.clone())
320            }
321            Lang::Operator {
322                operator: Op::Dot(_),
323                rhs: e1,
324                lhs: e2,
325                ..
326            }
327            | Lang::Operator {
328                operator: Op::Pipe(_),
329                rhs: e1,
330                lhs: e2,
331                ..
332            } => {
333                let e1 = (**e1).clone();
334                let e2 = (**e2).clone();
335                match e2.clone() {
336                    Lang::Variable { .. } => match e1 {
337                        Lang::Integer { .. } => Translatable::from(cont.clone())
338                            .to_r(&e2)
339                            .add("[[")
340                            .to_r(&e1)
341                            .add("]]")
342                            .into(),
343                        _ => Translatable::from(cont.clone())
344                            .to_r(&e2)
345                            .add("[['")
346                            .to_r(&e1)
347                            .add("']]")
348                            .into(),
349                    },
350                    Lang::List { value: fields, .. } => {
351                        let at = fields[0].clone();
352                        Translatable::from(cont.clone())
353                            .add("within(")
354                            .to_r(&e2)
355                            .add(", { ")
356                            .add(&at.get_argument())
357                            .add(" <- ")
358                            .to_r(&at.get_value())
359                            .add(" })")
360                            .into()
361                    }
362                    Lang::DataFrame { value: fields, .. } => {
363                        let at = fields[0].clone();
364                        Translatable::from(cont.clone())
365                            .add("within(")
366                            .to_r(&e2)
367                            .add(", { ")
368                            .add(&at.get_argument())
369                            .add(" <- ")
370                            .to_r(&at.get_value())
371                            .add(" })")
372                            .into()
373                    }
374                    Lang::FunctionApp {
375                        identifier: var,
376                        arguments: v,
377                        help_data: h,
378                    } => {
379                        let v = [e1].iter().chain(v.iter()).cloned().collect();
380                        Lang::FunctionApp {
381                            identifier: var,
382                            arguments: v,
383                            help_data: h,
384                        }
385                        .to_r(cont)
386                    }
387                    _ => Translatable::from(cont.clone())
388                        .to_r(&e2)
389                        .add("[[")
390                        .add("]]")
391                        .to_r(&e1)
392                        .into(),
393                }
394            }
395            Lang::Operator {
396                operator: Op::Dollar(_),
397                rhs: e1,
398                lhs: e2,
399                ..
400            } => {
401                let e1 = (**e1).clone();
402                let e2 = (**e2).clone();
403                let t1 = typing(cont, &e1).value;
404                let val = match (t1.clone(), e2.clone()) {
405                    (Type::Vec(vtype, _, _, _), Lang::Variable { name, .. })
406                        if vtype.is_array() =>
407                    {
408                        format!("vec_apply(get, {}, typed_vec('{}'))", e1.to_r(cont).0, name)
409                    }
410                    (Type::Vec(VecType::S3, _, _, _), Lang::Variable { name, .. }) => {
411                        let name_str = name.replace("__", ".");
412                        format!("get({}, '{}')", e1.to_r(cont).0, name_str)
413                    }
414                    (_, Lang::Variable { name, .. }) => format!("{}${}", e1.to_r(cont).0, name),
415                    _ => format!("{}${}", e1.to_r(cont).0, e2.to_r(cont).0),
416                };
417                (val, cont.clone())
418            }
419            Lang::Operator {
420                operator: op,
421                rhs: e1,
422                lhs: e2,
423                ..
424            } => {
425                let op_str = format!(" {} ", op);
426                Translatable::from(cont.clone())
427                    .to_r(e1)
428                    .add(&op_str)
429                    .to_r(e2)
430                    .into()
431            }
432            Lang::Scope { body: exps, .. } => Translatable::from(cont.clone())
433                .add("{\n")
434                .join(exps, "\n")
435                .add("\n}")
436                .into(),
437            Lang::Function {
438                parameters: params,
439                body,
440                ..
441            } => {
442                let fn_type = FunctionType::try_from(typing(cont, self).value.clone())
443                    .expect("function expression should have a function type");
444                let return_type = fn_type.get_return_type();
445
446                // Record alias constructors take specific named fields — calling
447                // TypeName(single_value) would fail.  The body already constructs
448                // the correct type (via ConstructorCall or List), so skip the
449                // output conversion for record aliases.
450                let is_record_alias_return = match &return_type {
451                    Type::Alias(alias_name, _, _, _) => cont
452                        .aliases()
453                        .find(|(var, _)| var.get_name() == *alias_name)
454                        .map(|(_, t)| matches!(t, Type::Record(_, _)))
455                        .unwrap_or(false),
456                    _ => false,
457                };
458                let output_conversion = if is_record_alias_return {
459                    "".to_string()
460                } else {
461                    cont.get_type_anotation(&return_type)
462                };
463
464                let has_variadic = params.last().map(|p| p.is_variadic()).unwrap_or(false);
465                let list_of_types = params
466                    .iter()
467                    .map(ArgumentType::get_type)
468                    .collect::<Vec<_>>();
469                let sub_context = params
470                    .iter()
471                    .map(|arg_typ| arg_typ.clone().to_var(cont))
472                    .zip(list_of_types.clone())
473                    .fold(cont.clone(), |context: Context, (var, typ)| {
474                        context.clone().push_var_type(var, typ, &context)
475                    });
476                let res = if output_conversion.is_empty() {
477                    "".to_string()
478                } else {
479                    " |> ".to_owned() + &output_conversion
480                };
481                let body_r = body.to_r(&sub_context).0;
482                let final_body_r = if has_variadic {
483                    let vname = params.last().unwrap().get_argument_str();
484                    // inject `vname <- list(...)` after opening `{`
485                    if body_r.starts_with('{') {
486                        format!("{{\n{} <- list(...){}", vname, &body_r[1..])
487                    } else {
488                        body_r
489                    }
490                } else {
491                    body_r
492                };
493                (
494                    format!(
495                        "(function({}) {}{}) |> {}",
496                        params
497                            .iter()
498                            .map(|x| x.to_r())
499                            .collect::<Vec<_>>()
500                            .join(", "),
501                        final_body_r,
502                        res,
503                        cont.get_type_anotation(&fn_type.into())
504                    ),
505                    cont.clone(),
506                )
507            }
508            Lang::Variable { .. } => {
509                //Here we only keep the variable name, the path and the type
510                let var = Var::from_language(self.clone()).unwrap();
511                let name = if var.contains("__") {
512                    var.replace("__", ".").get_name()
513                } else {
514                    var.display_type(cont).get_name()
515                };
516                (name.to_string(), cont.clone())
517            }
518            Lang::FunctionApp {
519                identifier: exp,
520                arguments: vals,
521                ..
522            } => {
523                let var = Var::try_from(exp.clone()).unwrap();
524
525                let (exp_str, cont1) = exp.to_r(cont);
526                let fn_t = FunctionType::try_from(
527                    cont1
528                        .get_type_from_variable(&var)
529                        .unwrap_or_else(|_| panic!("variable {} don't have a related type", var)),
530                )
531                .map(|ft| ft.adjust_nb_parameters(vals.len()))
532                .expect("function application identifier should have a function type");
533                let new_args = fn_t
534                    .get_param_types()
535                    .iter()
536                    .map(|arg| reduce_type(&cont1, arg))
537                    .collect::<Vec<_>>();
538                let new_vals = vals
539                    .iter()
540                    .zip(new_args.iter())
541                    .map(set_related_type_if_variable)
542                    .collect::<Vec<_>>();
543                let (args, current_cont) = Translatable::from(cont1).join(&new_vals, ", ").into();
544                Var::from_language(*exp.clone())
545                    .map(|var| {
546                        let name = var.get_name();
547                        let new_name = if &name[0..1] == "%" {
548                            format!("`{}`", name.replace("__", "."))
549                        } else {
550                            name.replace("__", ".")
551                        };
552                        (format!("{}({})", new_name, args), current_cont.clone())
553                    })
554                    .unwrap_or((format!("{}({})", exp_str, args), current_cont))
555            }
556            Lang::VecFunctionApp {
557                identifier: exp,
558                arguments: vals,
559                ..
560            } => {
561                let var = Var::try_from(exp.clone()).unwrap();
562                let name = var.get_name();
563                let str_vals = vals
564                    .iter()
565                    .map(|x| x.to_r(cont).0)
566                    .collect::<Vec<_>>()
567                    .join(", ");
568                if name == "reduce" {
569                    (format!("vec_reduce({})", str_vals), cont.clone())
570                } else if name == "extend" {
571                    (format!("vec_extend({})", str_vals), cont.clone())
572                } else if cont.is_an_untyped_function(&name) {
573                    let name = name.replace("__", ".");
574                    let new_name = if &name[0..1] == "%" {
575                        format!("`{}`", name)
576                    } else {
577                        name.to_string()
578                    };
579                    let s = format!("vec_apply({}, {})", new_name, str_vals);
580                    (s, cont.clone())
581                } else {
582                    let (exp_str, cont1) = exp.to_r(cont);
583                    let fn_t = FunctionType::try_from(
584                        cont1.get_type_from_variable(&var).unwrap_or_else(|_| {
585                            panic!("variable {} don't have a related type", var)
586                        }),
587                    )
588                    .expect("vector function application identifier should have a function type");
589                    let new_args = fn_t
590                        .get_param_types()
591                        .iter()
592                        .map(|arg| reduce_type(&cont1, arg))
593                        .collect::<Vec<_>>();
594                    let new_vals = vals
595                        .iter()
596                        .zip(new_args.iter())
597                        .map(set_related_type_if_variable)
598                        .collect::<Vec<_>>();
599                    let (args, current_cont) =
600                        Translatable::from(cont1).join(&new_vals, ", ").into();
601                    Var::from_language(*exp.clone())
602                        .map(|var| {
603                            let name = var.get_name();
604                            let new_name = if &name[0..1] == "%" {
605                                format!("`{}`", name.replace("__", "."))
606                            } else {
607                                name.replace("__", ".")
608                            };
609                            (
610                                format!("vec_apply({}, {})", new_name, args),
611                                current_cont.clone(),
612                            )
613                        })
614                        .unwrap_or((format!("vec_apply({}, {})", exp_str, args), current_cont))
615                }
616            }
617            Lang::ArrayIndexing {
618                identifier: exp,
619                indexing: val,
620                ..
621            } => {
622                let (exp_str, _) = exp.to_r(cont);
623                let (val_str, _) = val.to_simple_r(cont);
624                let (typ, _, _) = typing(cont, exp).to_tuple();
625                let res = match typ {
626                    _ => format!("{}[[{}]]", exp_str, val_str),
627                };
628                (res, cont.clone())
629            }
630            Lang::GenFunc { name: func, .. } => (
631                format!("function(x, ...) UseMethod('{}')", func),
632                cont.clone(),
633            ),
634            Lang::Let {
635                variable: expr,
636                r#type: ttype,
637                expression: body,
638                is_public: _,
639                help_data: _,
640            } => {
641                let (body_str, new_cont) = body.to_r(cont);
642                let new_name = format_backtick(expr.clone().to_r(cont).0);
643
644                let (r_code, _new_name2) = Function::try_from((**body).clone())
645                    .map(|_| {
646                        let related_type = Var::try_from(expr)
647                            .ok()
648                            .map(|v| v.get_type())
649                            .filter(|t| !matches!(t, Type::Empty(_) | Type::UnknownFunction(_)))
650                            .unwrap_or_else(|| typing(cont, expr).value);
651                        let method = match cont.get_environment() {
652                            Environment::Project => format!(
653                                "#' @method {}\n",
654                                new_name.replace(".", " ").replace("`", "")
655                            ),
656                            _ => "".to_string(),
657                        };
658                        match related_type {
659                            Type::Empty(_) => {
660                                (format!("{} <- {}", new_name, body_str), new_name.clone())
661                            }
662                            Type::Any(_) | Type::Generic(_, _) => (
663                                format!("{}.default <- {}", new_name, body_str),
664                                new_name.clone(),
665                            ),
666                            _ => (
667                                format!("{}{} <- {}", method, new_name, body_str),
668                                new_name.clone(),
669                            ),
670                        }
671                    })
672                    .unwrap_or((format!("{} <- {}", new_name, body_str), new_name));
673                let code = if !ttype.is_empty() {
674                    let type_annotation = new_cont.get_type_anotation(ttype);
675                    format!("{} |> {}\n", r_code, type_annotation)
676                } else {
677                    r_code + "\n"
678                };
679                (code, new_cont)
680            }
681            Lang::Array { .. } => {
682                let typ = self.typing(cont).value;
683
684                let dimension = ArrayType::try_from(typ.clone())
685                    .expect("array literal should have an array type")
686                    .get_shape()
687                    .map(|sha| format!("c({})", sha))
688                    .unwrap_or_else(|| "c(0)".to_string());
689
690                let array = &self
691                    .linearize_array()
692                    .iter()
693                    .map(|lang| lang.to_r(cont).0)
694                    .collect::<Vec<_>>()
695                    .join(", ")
696                    .and_if(|lin_array| !lin_array.is_empty())
697                    .map(|lin_array| format!("typed_vec({}, dim = {})", lin_array, dimension))
698                    .unwrap_or("logical(0)".to_string());
699
700                (
701                    format!("{} |> {}", array, cont.get_type_anotation(&typ)),
702                    cont.to_owned(),
703                )
704            }
705            Lang::List { value: args, .. } => {
706                let (body, current_cont) = Translatable::from(cont.clone())
707                    .join_arg_val(args, ",\n ")
708                    .into();
709                let (typ, _, _) = typing(cont, self).to_tuple();
710                // For record-alias types use the constructor directly
711                if let Type::Alias(alias_name, _, _, _) = &typ {
712                    let is_record = cont
713                        .aliases()
714                        .find(|(var, _)| var.get_name() == *alias_name)
715                        .map(|(_, t)| matches!(t, Type::Record(_, _)))
716                        .unwrap_or(false);
717                    if is_record {
718                        return (format!("{}({})", alias_name, body), current_cont);
719                    }
720                }
721                let anotation = cont.get_type_anotation(&typ);
722                cont.get_classes(&typ)
723                    .map(|_| format!("list({}) |> {}", body, anotation))
724                    .unwrap_or(format!("list({}) |> {}", body, anotation))
725                    .to_some()
726                    .map(|s| (s, current_cont))
727                    .unwrap()
728            }
729            Lang::DataFrame { value: args, .. } => {
730                let (body, current_cont) = Translatable::from(cont.clone())
731                    .join_arg_val(args, ",\n ")
732                    .into();
733                let (typ, _, _) = typing(cont, self).to_tuple();
734                let anotation = cont.get_type_anotation(&typ);
735                cont.get_classes(&typ)
736                    .map(|_| format!("data.frame({}) |> {}", body, anotation))
737                    .unwrap_or(format!("data.frame({}) |> {}", body, anotation))
738                    .to_some()
739                    .map(|s| (s, current_cont))
740                    .unwrap()
741            }
742            Lang::If {
743                condition: cond,
744                if_block: exp,
745                else_block: els,
746                ..
747            } if els == &Box::new(Lang::Empty(HelpData::default())) => {
748                Translatable::from(cont.clone())
749                    .add("if(")
750                    .to_r(cond)
751                    .add(") {\n")
752                    .to_r(exp)
753                    .add(" \n}")
754                    .into()
755            }
756            Lang::If {
757                condition: cond,
758                if_block: exp,
759                else_block: els,
760                help_data: _,
761            } => Translatable::from(cont.clone())
762                .add("if(")
763                .to_r(cond)
764                .add(") {\n")
765                .to_r(exp)
766                .add(" \n} else ")
767                .to_r(els)
768                .into(),
769            Lang::Tuple { value: vals, .. } => Translatable::from(cont.clone())
770                .add("struct(list(")
771                .join(vals, ", ")
772                .add("), 'Tuple')")
773                .into(),
774            Lang::Assign {
775                identifier: var,
776                expression: exp,
777                ..
778            } => Translatable::from(cont.clone())
779                .to_r(var)
780                .add(" <- ")
781                .to_r(exp)
782                .into(),
783            Lang::Comment { value: txt, .. } => ("#".to_string() + &txt, cont.clone()),
784            Lang::Tag {
785                name: s, value: t, ..
786            } => {
787                let (t_str, new_cont) = t.to_r(cont);
788                let (typ, _, _) = typing(cont, self).to_tuple();
789                let anotation = cont.get_type_anotation(&typ);
790                (
791                    format!(
792                        "structure(list('{}', body = {}), class = c('.{}', 'Tag')) |> {}",
793                        s, t_str, s, anotation
794                    ),
795                    new_cont,
796                )
797            }
798            Lang::Null(_) => ("NULL".to_string(), cont.clone()),
799            Lang::Empty(_) => ("NA".to_string(), cont.clone()),
800            Lang::Lines { value: exps, .. } => {
801                Translatable::from(cont.clone()).join(exps, "\n").into()
802            }
803            Lang::Return { value: exp, .. } => Translatable::from(cont.clone())
804                .add("return ")
805                .to_r(exp)
806                .into(),
807            Lang::Lambda {
808                parameters: params,
809                body: bloc,
810                ..
811            } => {
812                let param_names: Vec<String> = params
813                    .iter()
814                    .map(|p: &Lang| match p {
815                        Lang::Variable { name, .. } => name.clone(),
816                        _ => "x".to_string(),
817                    })
818                    .collect();
819                (
820                    format!(
821                        "function({}) {{ {} }}",
822                        param_names.join(", "),
823                        bloc.to_r(cont).0
824                    ),
825                    cont.clone(),
826                )
827            }
828            Lang::VecBlock { value: bloc, .. } => (bloc.to_string(), cont.clone()),
829            Lang::Library { value: name, .. } => (format!("library({})", name), cont.clone()),
830            Lang::Match {
831                target: exp,
832                branches,
833                ..
834            } => (
835                to_pattern_match_statement((**exp).clone(), branches, cont),
836                cont.clone(),
837            ),
838            Lang::Exp { value: exp, .. } => (exp.clone(), cont.clone()),
839            Lang::ForLoop {
840                identifier: var,
841                expression: iterator,
842                body,
843                ..
844            } => Translatable::from(cont.clone())
845                .add("for (")
846                .to_r_safe(var)
847                .add(" in ")
848                .to_r_safe(iterator)
849                .add(") {\n")
850                .to_r_safe(body)
851                .add("\n}")
852                .into(),
853            Lang::RFunction {
854                parameters: vars,
855                body,
856                ..
857            } => Translatable::from(cont.clone())
858                .add("function (")
859                .join(vars, ", ")
860                .add(") \n")
861                .add(body)
862                .add("\n")
863                .into(),
864            Lang::Signature { .. } => ("".to_string(), cont.clone()),
865            Lang::Alias {
866                identifier: ident,
867                target_type: typ,
868                ..
869            } => {
870                let name = Var::from_language(*ident.clone())
871                    .map(|v| v.get_name())
872                    .unwrap_or_default();
873                match typ {
874                    Type::Record(fields, _) => {
875                        let mut sorted_fields: Vec<&ArgumentType> = fields.iter().collect();
876                        sorted_fields.sort_by_key(|f| f.get_argument_str());
877                        let params = sorted_fields
878                            .iter()
879                            .map(|f| f.get_argument_str())
880                            .collect::<Vec<_>>()
881                            .join(", ");
882                        let field_args = sorted_fields
883                            .iter()
884                            .map(|f| {
885                                let n = f.get_argument_str();
886                                format!("{n} = {n}")
887                            })
888                            .collect::<Vec<_>>()
889                            .join(", ");
890                        let constructor = format!(
891                            "{name} <- function({params}) {{\n  structure(list({field_args}), class = c(\"{name}\", \"list\"))\n}}"
892                        );
893                        let fields_quoted = sorted_fields
894                            .iter()
895                            .map(|f| format!("\"{}\"", f.get_argument_str()))
896                            .collect::<Vec<_>>()
897                            .join(", ");
898                        let field_access = sorted_fields
899                            .iter()
900                            .map(|f| {
901                                let n = f.get_argument_str();
902                                format!("{n} = x[[\"{n}\"]]")
903                            })
904                            .collect::<Vec<_>>()
905                            .join(", ");
906                        let validator = format!(
907                            ".validate_{name} <- function(x) {{\n  required_fields <- c({fields_quoted})\n  missing_fields <- setdiff(required_fields, names(x))\n  if (length(missing_fields) > 0) {{\n    stop(paste0(\"Validation failed for type {name}: missing fields: \", paste(missing_fields, collapse = \", \")))\n  }}\n  {name}({field_access})\n}}"
908                        );
909                        (
910                            format!("{constructor}\n{validator}"),
911                            cont.clone(),
912                        )
913                    }
914                    Type::Operator(_, _, _, _) => {
915                        // Union alias: generate constructors for each variant
916                        let union_name = &name;
917                        let members = flatten_operator_union(typ);
918                        // Sort for deterministic output
919                        let mut members_vec: Vec<Type> = members.into_iter().collect();
920                        members_vec.sort_by_key(|t| t.pretty2());
921                        let constructors: Vec<String> = members_vec
922                            .iter()
923                            .filter_map(|member| match member {
924                                Type::Tag(variant_name, inner, _) => {
925                                    match inner.as_ref() {
926                                        Type::Empty(_) => Some(format!(
927                                            "{variant_name} <- function() {{\n  structure(list(), class = c(\"{variant_name}\", \"{union_name}\", \"list\"))\n}}"
928                                        )),
929                                        _ => {
930                                            // Tag with payload: wrap as single-field constructor
931                                            Some(format!(
932                                                "{variant_name} <- function(x) {{\n  structure(list(x), class = c(\"{variant_name}\", \"{union_name}\", \"list\"))\n}}"
933                                            ))
934                                        }
935                                    }
936                                }
937                                Type::Alias(alias_name, _, _, _) => {
938                                    // Look up the record fields for this alias
939                                    let record_fields = cont
940                                        .aliases()
941                                        .find(|(var, _)| var.get_name() == *alias_name)
942                                        .and_then(|(_, t)| {
943                                            if let Type::Record(fields, _) = t {
944                                                Some(fields.clone())
945                                            } else {
946                                                None
947                                            }
948                                        });
949                                    if let Some(fields) = record_fields {
950                                        let mut sorted: Vec<&ArgumentType> =
951                                            fields.iter().collect();
952                                        sorted.sort_by_key(|f| f.get_argument_str());
953                                        let params = sorted
954                                            .iter()
955                                            .map(|f| f.get_argument_str())
956                                            .collect::<Vec<_>>()
957                                            .join(", ");
958                                        let field_args = sorted
959                                            .iter()
960                                            .map(|f| {
961                                                let n = f.get_argument_str();
962                                                format!("{n} = {n}")
963                                            })
964                                            .collect::<Vec<_>>()
965                                            .join(", ");
966                                        Some(format!(
967                                            "{alias_name} <- function({params}) {{\n  structure(list({field_args}), class = c(\"{alias_name}\", \"{union_name}\", \"list\"))\n}}"
968                                        ))
969                                    } else {
970                                        None
971                                    }
972                                }
973                                _ => None,
974                            })
975                            .collect();
976                        (constructors.join("\n"), cont.clone())
977                    }
978                    Type::Integer(tint, _) => {
979                        use crate::components::r#type::tint::Tint;
980                        let validator = match tint {
981                            Tint::Val(i) => format!(
982                                ".validate_{name} <- function(x) {{\n  if (!is.integer(x)) stop(\"Validation failed for type {name}: expected int\")\n  if (x != {i}L) stop(\"Validation failed for type {name}: expected literal {i}\")\n  x\n}}"
983                            ),
984                            Tint::Unknown => format!(
985                                ".validate_{name} <- function(x) {{\n  if (!is.integer(x)) stop(\"Validation failed for type {name}: expected int\")\n  x\n}}"
986                            ),
987                        };
988                        (validator, cont.clone())
989                    }
990                    Type::Char(tchar, _) => {
991                        use crate::components::r#type::tchar::Tchar;
992                        let validator = match tchar {
993                            Tchar::Val(s) => format!(
994                                ".validate_{name} <- function(x) {{\n  if (!is.character(x)) stop(\"Validation failed for type {name}: expected char\")\n  if (x != '{s}') stop(\"Validation failed for type {name}: expected literal '{s}'\")\n  x\n}}"
995                            ),
996                            Tchar::Unknown => format!(
997                                ".validate_{name} <- function(x) {{\n  if (!is.character(x)) stop(\"Validation failed for type {name}: expected char\")\n  x\n}}"
998                            ),
999                        };
1000                        (validator, cont.clone())
1001                    }
1002                    Type::Boolean(tbool, _) => {
1003                        use crate::components::r#type::tbool::Tbool;
1004                        let validator = match tbool {
1005                            Tbool::Val(b) => {
1006                                let r_val = if *b { "TRUE" } else { "FALSE" };
1007                                format!(
1008                                    ".validate_{name} <- function(x) {{\n  if (!is.logical(x)) stop(\"Validation failed for type {name}: expected bool\")\n  if (x != {r_val}) stop(\"Validation failed for type {name}: expected literal {r_val}\")\n  x\n}}"
1009                                )
1010                            }
1011                            Tbool::Unknown => format!(
1012                                ".validate_{name} <- function(x) {{\n  if (!is.logical(x)) stop(\"Validation failed for type {name}: expected bool\")\n  x\n}}"
1013                            ),
1014                        };
1015                        (validator, cont.clone())
1016                    }
1017                    Type::Number(tnum, _) => {
1018                        use crate::components::r#type::tnumber::Tnum;
1019                        let validator = match tnum {
1020                            Tnum::Val(v) => format!(
1021                                ".validate_{name} <- function(x) {{\n  if (!is.numeric(x)) stop(\"Validation failed for type {name}: expected num\")\n  if (x != {v}) stop(\"Validation failed for type {name}: expected literal {v}\")\n  x\n}}"
1022                            ),
1023                            Tnum::Unknown => format!(
1024                                ".validate_{name} <- function(x) {{\n  if (!is.numeric(x)) stop(\"Validation failed for type {name}: expected num\")\n  x\n}}"
1025                            ),
1026                        };
1027                        (validator, cont.clone())
1028                    }
1029                    Type::Tag(tag_name, inner_type, _) => {
1030                        let body_validation = match inner_type.as_ref() {
1031                            Type::Empty(_) => String::new(),
1032                            Type::Integer(tint, _) => {
1033                                use crate::components::r#type::tint::Tint;
1034                                let null_check = format!("\n  if (is.null(x[[\"body\"]])) stop(\"Validation failed for type {name}: missing 'body' field\")\n  if (!is.integer(x[[\"body\"]])) stop(\"Validation failed for type {name}: body must be int\")");
1035                                match tint {
1036                                    Tint::Val(i) => format!("{null_check}\n  if (x[[\"body\"]] != {i}L) stop(\"Validation failed for type {name}: body must be literal {i}\")"),
1037                                    Tint::Unknown => null_check,
1038                                }
1039                            }
1040                            Type::Char(tchar, _) => {
1041                                use crate::components::r#type::tchar::Tchar;
1042                                let null_check = format!("\n  if (is.null(x[[\"body\"]])) stop(\"Validation failed for type {name}: missing 'body' field\")\n  if (!is.character(x[[\"body\"]])) stop(\"Validation failed for type {name}: body must be char\")");
1043                                match tchar {
1044                                    Tchar::Val(s) => format!("{null_check}\n  if (x[[\"body\"]] != '{s}') stop(\"Validation failed for type {name}: body must be literal '{s}'\")"),
1045                                    Tchar::Unknown => null_check,
1046                                }
1047                            }
1048                            Type::Boolean(tbool, _) => {
1049                                use crate::components::r#type::tbool::Tbool;
1050                                let null_check = format!("\n  if (is.null(x[[\"body\"]])) stop(\"Validation failed for type {name}: missing 'body' field\")\n  if (!is.logical(x[[\"body\"]])) stop(\"Validation failed for type {name}: body must be bool\")");
1051                                match tbool {
1052                                    Tbool::Val(b) => {
1053                                        let r_val = if *b { "TRUE" } else { "FALSE" };
1054                                        format!("{null_check}\n  if (x[[\"body\"]] != {r_val}) stop(\"Validation failed for type {name}: body must be literal {r_val}\")")
1055                                    }
1056                                    Tbool::Unknown => null_check,
1057                                }
1058                            }
1059                            Type::Number(tnum, _) => {
1060                                use crate::components::r#type::tnumber::Tnum;
1061                                let null_check = format!("\n  if (is.null(x[[\"body\"]])) stop(\"Validation failed for type {name}: missing 'body' field\")\n  if (!is.numeric(x[[\"body\"]])) stop(\"Validation failed for type {name}: body must be num\")");
1062                                match tnum {
1063                                    Tnum::Val(v) => format!("{null_check}\n  if (x[[\"body\"]] != {v}) stop(\"Validation failed for type {name}: body must be literal {v}\")"),
1064                                    Tnum::Unknown => null_check,
1065                                }
1066                            }
1067                            Type::Alias(alias_name, _, _, _) => format!(
1068                                "\n  if (is.null(x[[\"body\"]])) stop(\"Validation failed for type {name}: missing 'body' field\")\n  .validate_{alias_name}(x[[\"body\"]])"
1069                            ),
1070                            _ => format!(
1071                                "\n  if (is.null(x[[\"body\"]])) stop(\"Validation failed for type {name}: missing 'body' field\")"
1072                            ),
1073                        };
1074                        let validator = format!(
1075                            ".validate_{name} <- function(x) {{\n  if (x[[1]] != '{tag_name}') stop(\"Validation failed for type {name}: expected tag '{tag_name}'\")\n{body_validation}\n  x\n}}"
1076                        );
1077                        (validator, cont.clone())
1078                    }
1079                    _ => ("".to_string(), cont.clone()),
1080                }
1081            }
1082            Lang::UnionConstructor {
1083                variant_name,
1084                fields,
1085                ..
1086            } => {
1087                if fields.is_empty() {
1088                    (format!("{}()", variant_name), cont.clone())
1089                } else {
1090                    let (body, current_cont) = Translatable::from(cont.clone())
1091                        .join_arg_val(fields, ", ")
1092                        .into();
1093                    (format!("{}({})", variant_name, body), current_cont)
1094                }
1095            }
1096            Lang::KeyValue {
1097                key: k, value: v, ..
1098            } => (format!("{} = {}", k, v.to_r(cont).0), cont.clone()),
1099            Lang::Vector { value: vals, .. } => {
1100                let res = "c(".to_string()
1101                    + &vals
1102                        .iter()
1103                        .map(|x: &Lang| x.to_r(cont).0)
1104                        .collect::<Vec<_>>()
1105                        .join(", ")
1106                    + ")";
1107                (res, cont.to_owned())
1108            }
1109            Lang::Not { value: exp, .. } => (format!("!{}", exp.to_r(cont).0), cont.clone()),
1110            Lang::Sequence { body: vals, .. } => {
1111                let res = if !vals.is_empty() {
1112                    "c(".to_string()
1113                        + &vals
1114                            .iter()
1115                            .map(|x: &Lang| "list(".to_string() + &x.to_r(cont).0 + ")")
1116                            .collect::<Vec<_>>()
1117                            .join(", ")
1118                        + ")"
1119                } else {
1120                    "c(list())".to_string()
1121                };
1122                (res, cont.to_owned())
1123            }
1124            Lang::TestBlock {
1125                value: body,
1126                help_data: h,
1127            } => {
1128                let file_name = h
1129                    .get_file_data()
1130                    .map(|(name, _)| format!("test-{}", name))
1131                    .unwrap_or_else(|| "test-unknown".to_string())
1132                    .replace("TypR/", "")
1133                    .replace(".ty", ".R");
1134
1135                let file_path = format!("tests/testthat/{}", file_name);
1136                let content = body.to_r(cont).0;
1137
1138                let _ = write_output_file(&file_path, &content);
1139                ("".to_string(), cont.clone())
1140            }
1141            Lang::JSBlock(exp, _id, _h) => {
1142                let js_cont = Context::default(); //TODO get js context from memory
1143                let res = exp.to_js(&js_cont).0;
1144                (format!("'{}{}'", JS_HEADER, res), cont.clone())
1145            }
1146            Lang::WhileLoop {
1147                condition, body, ..
1148            } => (
1149                format!(
1150                    "while ({}) {{\n{}\n}}",
1151                    condition.to_r(cont).0,
1152                    body.to_r(cont).0
1153                ),
1154                cont.clone(),
1155            ),
1156            Lang::Loop { body, .. } => (
1157                format!("while (TRUE) {{\n{}\n}}", body.to_r(cont).0),
1158                cont.clone(),
1159            ),
1160            Lang::Break(_) => ("break".to_string(), cont.clone()),
1161            Lang::NA(_) => ("NA".to_string(), cont.clone()),
1162            Lang::Module {
1163                name,
1164                body,
1165                module_position: position,
1166                config,
1167                ..
1168            } => {
1169                let name_str = if (name == "main") && (config.environment == Environment::Project) {
1170                    "a_main"
1171                } else {
1172                    name
1173                };
1174
1175                let body_content = body
1176                    .iter()
1177                    .map(|lang| lang.to_r(cont).0)
1178                    .collect::<Vec<_>>()
1179                    .join("\n");
1180
1181                // Build exports (inside local) and generics (outside local) for @pub members
1182                let mut exports: Vec<String> = Vec::new();
1183                let mut generics: Vec<String> = Vec::new();
1184                let mut generic_exports: Vec<String> = Vec::new();
1185
1186                for lang in body.iter() {
1187                    if let Lang::Let {
1188                        variable: var,
1189                        is_public: true,
1190                        ..
1191                    } = lang
1192                    {
1193                        if let Some(v) = Var::from_language(*var.clone()) {
1194                            let raw_name = v.get_name();
1195                            let typed_name = v.clone().display_type(cont).get_name();
1196
1197                            // Export the (possibly type-suffixed) member into the module env
1198                            exports.push(format!("{}${} <- {}", name_str, typed_name, typed_name));
1199
1200                            // For typed functions: register as S3 method and create generic
1201                            let var_type = v.get_type();
1202                            if !var_type.is_empty() && typed_name != raw_name {
1203                                let class_name = cont.get_class_unquoted(&var_type);
1204                                exports.push(format!(
1205                                    "registerS3method(\"{}\", \"{}\", {})",
1206                                    raw_name, class_name, typed_name
1207                                ));
1208
1209                                let generic_def = format!(
1210                                    "{} <- function(x, ...) UseMethod(\"{}\")",
1211                                    raw_name, raw_name
1212                                );
1213                                if !generics.contains(&generic_def) {
1214                                    generics.push(generic_def);
1215                                    generic_exports
1216                                        .push(format!("{}${} <- {}", name_str, raw_name, raw_name));
1217                                }
1218                            }
1219                        }
1220                    }
1221                    // Export @pub opaque type constructors into the module environment
1222                    if let Lang::Alias {
1223                        identifier: var,
1224                        is_public: true,
1225                        ..
1226                    } = lang
1227                    {
1228                        if let Some(v) = Var::from_language(*var.clone()) {
1229                            let alias_name = v.get_name();
1230                            exports.push(format!("{}${} <- {}", name_str, alias_name, alias_name));
1231                        }
1232                    }
1233                }
1234
1235                let exports_str = if exports.is_empty() {
1236                    String::new()
1237                } else {
1238                    "\n".to_string() + &exports.join("\n")
1239                };
1240
1241                let generics_defs_str = if generics.is_empty() {
1242                    String::new()
1243                } else {
1244                    generics.join("\n") + "\n"
1245                };
1246
1247                let generic_exports_str = if generic_exports.is_empty() {
1248                    String::new()
1249                } else {
1250                    "\n".to_string() + &generic_exports.join("\n")
1251                };
1252
1253                let content = format!(
1254                    "{}{} <- new.env(parent = emptyenv())\nlocal({{\n{}{}\n}}){}",
1255                    generics_defs_str, name_str, body_content, exports_str, generic_exports_str
1256                );
1257
1258                match (position, config.environment) {
1259                    (ModulePosition::Internal, _) => (content, cont.clone()),
1260                    // In WASM mode, inline all external modules instead of writing files
1261                    (ModulePosition::External, Environment::Wasm) => {
1262                        let file_path = format!("{}.R", name_str);
1263                        let _ = write_output_file(&file_path, &content);
1264                        (content, cont.clone())
1265                    }
1266                    (ModulePosition::External, Environment::StandAlone)
1267                    | (ModulePosition::External, Environment::Repl) => {
1268                        let file_path = format!("{}.R", name_str);
1269                        let _ = write_output_file(&file_path, &content);
1270                        (format!("source('{}')", file_path), cont.clone())
1271                    }
1272                    (ModulePosition::External, Environment::Project) => {
1273                        let file_path = format!("R/{}.R", name_str);
1274                        let _ = write_output_file(&file_path, &content);
1275                        (format!("#' @include {}.R", name_str), cont.clone())
1276                    }
1277                }
1278            }
1279            Lang::UseModule {
1280                module_path,
1281                selector,
1282                ..
1283            } => {
1284                use crate::components::language::use_lang::UseSelector;
1285
1286                // Build the R accessor prefix: A::B::C → A$B$C
1287                let r_path = module_path.join("$");
1288
1289                // Resolve the module type from context to enumerate public members for wildcards
1290                let mod_type_opt = (|| {
1291                    let root = cont
1292                        .get_type_from_variable(&Var::from_name(&module_path[0]))
1293                        .ok()?;
1294                    let mut current = root;
1295                    for seg in module_path.iter().skip(1) {
1296                        current = current
1297                            .to_module_type()
1298                            .ok()?
1299                            .get_type_from_name(seg)
1300                            .ok()?;
1301                    }
1302                    current.to_module_type().ok()
1303                })();
1304
1305                let bindings: Vec<String> = match selector {
1306                    UseSelector::Wildcard => mod_type_opt
1307                        .map(|mt| {
1308                            mt.get_public_members()
1309                                .iter()
1310                                .map(|m| {
1311                                    let name = m.get_argument_str();
1312                                    format!("{} <- {}${}", name, r_path, name)
1313                                })
1314                                .collect()
1315                        })
1316                        .unwrap_or_default(),
1317                    UseSelector::Items(items) => items
1318                        .iter()
1319                        .map(|item| {
1320                            let local_name = item.alias.as_deref().unwrap_or(&item.name);
1321                            format!("{} <- {}${}", local_name, r_path, item.name)
1322                        })
1323                        .collect(),
1324                };
1325
1326                (bindings.join("\n"), cont.clone())
1327            }
1328            Lang::ModuleImport { .. } => ("".to_string(), cont.clone()),
1329            Lang::ConstructorCall {
1330                type_name, fields, ..
1331            } => {
1332                let (body, current_cont) = Translatable::from(cont.clone())
1333                    .join_arg_val(fields, ", ")
1334                    .into();
1335                (format!("{}({})", type_name, body), current_cont)
1336            }
1337            Lang::ArrayConstructorCall {
1338                type_name,
1339                elements,
1340                help_data: h,
1341            } => {
1342                let temp_array = Lang::Array {
1343                    value: elements.clone(),
1344                    help_data: h.clone(),
1345                };
1346                let typ = temp_array.typing(cont).value;
1347                let dimension = ArrayType::try_from(typ)
1348                    .expect("array constructor call should have an array type")
1349                    .get_shape()
1350                    .map(|sha| format!("c({})", sha))
1351                    .unwrap_or_else(|| "c(0)".to_string());
1352                let lin_array = temp_array
1353                    .linearize_array()
1354                    .iter()
1355                    .map(|lang| lang.to_r(cont).0)
1356                    .collect::<Vec<_>>()
1357                    .join(", ");
1358                let inner = if lin_array.is_empty() {
1359                    "logical(0)".to_string()
1360                } else {
1361                    format!("typed_vec({}, dim = {})", lin_array, dimension)
1362                };
1363                (format!("{}({})", type_name, inner), cont.clone())
1364            }
1365            Lang::Import { .. } | Lang::Test { .. } | Lang::Use { .. } => {
1366                ("".to_string(), cont.clone())
1367            }
1368            Lang::ValidatingCast {
1369                expression,
1370                type_name,
1371                ..
1372            } => {
1373                let expr_r = expression.to_r(cont).0;
1374                (format!(".validate_{}({})", type_name, expr_r), cont.clone())
1375            }
1376            _ => ("".to_string(), cont.clone()),
1377        };
1378
1379        result
1380    }
1381}
1382
1383#[cfg(test)]
1384mod tests {
1385    use crate::utils::fluent_parser::FluentParser;
1386    use crate::components::language::{Lang, ModulePosition};
1387    use crate::components::context::config::{Config, Environment};
1388    use crate::components::context::Context;
1389    use crate::components::error_message::help_data::HelpData;
1390    use crate::processes::transpiling::translatable::RTranslatable;
1391
1392    #[test]
1393    fn test_validating_cast_transpiles_to_validate_call() {
1394        let r_code = FluentParser::new()
1395            .push("type Person <- list { name: char, age: int };")
1396            .run()
1397            .check_transpiling("x as! Person");
1398        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1399        assert!(
1400            r_str.contains(".validate_Person(x)"),
1401            "expected .validate_Person(x), got: {}",
1402            r_str
1403        );
1404    }
1405
1406    #[test]
1407    fn test_validating_cast_type_is_alias() {
1408        let typ = FluentParser::new()
1409            .push("type Person <- list { name: char, age: int };")
1410            .run()
1411            .check_typing("x as! Person");
1412        assert!(
1413            typ.pretty2().contains("Person"),
1414            "expected Alias(Person), got: {}",
1415            typ.pretty2()
1416        );
1417    }
1418
1419    #[test]
1420    fn test_alias_record_generates_validator() {
1421        let r_code = FluentParser::new()
1422            .check_transpiling("type Person <- list { name: char, age: int };");
1423        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1424        assert!(
1425            r_str.contains(".validate_Person <- function(x)"),
1426            "expected validator function, got: {}",
1427            r_str
1428        );
1429        assert!(
1430            r_str.contains("required_fields"),
1431            "expected field validation, got: {}",
1432            r_str
1433        );
1434    }
1435
1436    #[test]
1437    fn test_external_module_project_generates_include() {
1438        let module = Lang::Module {
1439            name: "MyModule".to_string(),
1440            body: vec![],
1441            module_position: ModulePosition::External,
1442            config: Config::default().set_environment(Environment::Project),
1443            help_data: HelpData::default(),
1444        };
1445        let context = Context::default().set_environment(Environment::Project);
1446        let (r_code, _) = module.to_r(&context);
1447        assert_eq!(r_code, "#' @include MyModule.R", "got: {}", r_code);
1448    }
1449
1450    #[test]
1451    fn test_module_transpilation_with_pub() {
1452        let r_code = FluentParser::new()
1453            .push("module Math { let sq <- 2; @pub let pi <- 3; };")
1454            .run()
1455            .get_r_code()
1456            .iter()
1457            .cloned()
1458            .collect::<Vec<_>>()
1459            .join("\n");
1460        assert!(
1461            r_code.contains("Math <- new.env(parent = emptyenv())"),
1462            "missing env init: {}",
1463            r_code
1464        );
1465        assert!(
1466            r_code.contains("local({"),
1467            "missing local block: {}",
1468            r_code
1469        );
1470        assert!(
1471            r_code.contains("Math$pi <- pi"),
1472            "missing public export: {}",
1473            r_code
1474        );
1475        assert!(
1476            !r_code.contains("Math$sq"),
1477            "private member should not be exported: {}",
1478            r_code
1479        );
1480    }
1481
1482    #[test]
1483    fn test_module_transpilation_no_pub() {
1484        let r_code = FluentParser::new()
1485            .push("module Empty { let x <- 1; };")
1486            .run()
1487            .get_r_code()
1488            .iter()
1489            .cloned()
1490            .collect::<Vec<_>>()
1491            .join("\n");
1492        assert!(
1493            r_code.contains("Empty <- new.env(parent = emptyenv())"),
1494            "missing env init: {}",
1495            r_code
1496        );
1497        assert!(
1498            r_code.contains("local({"),
1499            "missing local block: {}",
1500            r_code
1501        );
1502        assert!(
1503            !r_code.contains("Empty$x"),
1504            "private member should not be exported: {}",
1505            r_code
1506        );
1507    }
1508
1509    #[test]
1510    fn test_module_s3_registration_for_typed_pub_fn() {
1511        let r_code = FluentParser::new()
1512            .push("module Math { @pub let double <- fn(x: Integer): Integer { x }; };")
1513            .run()
1514            .get_r_code()
1515            .iter()
1516            .cloned()
1517            .collect::<Vec<_>>()
1518            .join("\n");
1519        assert!(
1520            r_code.contains("Math <- new.env(parent = emptyenv())"),
1521            "missing env init: {}",
1522            r_code
1523        );
1524        assert!(
1525            r_code.contains("registerS3method(\"double\", \"integer\", double.integer)"),
1526            "missing S3 registration: {}",
1527            r_code
1528        );
1529        assert!(
1530            r_code.contains("double <- function(x, ...) UseMethod(\"double\")"),
1531            "missing generic: {}",
1532            r_code
1533        );
1534        assert!(
1535            r_code.contains("Math$double <- double"),
1536            "missing generic export: {}",
1537            r_code
1538        );
1539    }
1540
1541    #[test]
1542    fn test_module_no_trailing_semicolon() {
1543        let r_code = FluentParser::new()
1544            .push("module Geo { @pub let pi <- 3; }")
1545            .run()
1546            .get_r_code()
1547            .iter()
1548            .cloned()
1549            .collect::<Vec<_>>()
1550            .join("\n");
1551        assert!(
1552            r_code.contains("Geo <- new.env(parent = emptyenv())"),
1553            "missing env init: {}",
1554            r_code
1555        );
1556        assert!(
1557            r_code.contains("Geo$pi <- pi"),
1558            "missing public export: {}",
1559            r_code
1560        );
1561    }
1562
1563    #[test]
1564    fn test_import_module() {
1565        let r_code = FluentParser::new()
1566            .push("module Math { @pub let pi <- 3; }")
1567            .push("import Math")
1568            .run()
1569            .run()
1570            .get_r_code()
1571            .iter()
1572            .cloned()
1573            .collect::<Vec<_>>()
1574            .join("\n");
1575        assert!(
1576            r_code.contains("Math <- new.env(parent = emptyenv())"),
1577            "missing env init: {}",
1578            r_code
1579        );
1580    }
1581
1582    #[test]
1583    fn test_import_module_as_alias() {
1584        let r_code = FluentParser::new()
1585            .push("module Math { @pub let pi <- 3; }")
1586            .push("import Math as Maths")
1587            .run()
1588            .run()
1589            .get_r_code()
1590            .iter()
1591            .cloned()
1592            .collect::<Vec<_>>()
1593            .join("\n");
1594        assert!(
1595            r_code.contains("Math <- new.env(parent = emptyenv())"),
1596            "missing env init: {}",
1597            r_code
1598        );
1599        assert!(
1600            r_code.contains("Maths <- Math") || r_code.contains("`Maths` <- Math"),
1601            "missing alias assignment: {}",
1602            r_code
1603        );
1604    }
1605
1606    #[test]
1607    fn test_use_items_transpiles() {
1608        let r_code = FluentParser::new()
1609            .push("module Math { @pub let pi <- 3; @pub let e <- 2; };")
1610            .push("use Math::{pi, e as euler};")
1611            .run()
1612            .run()
1613            .get_r_code()
1614            .iter()
1615            .cloned()
1616            .collect::<Vec<_>>()
1617            .join("\n");
1618        assert!(
1619            r_code.contains("pi <- Math$pi"),
1620            "missing pi binding: {}",
1621            r_code
1622        );
1623        assert!(
1624            r_code.contains("euler <- Math$e"),
1625            "missing euler binding: {}",
1626            r_code
1627        );
1628    }
1629
1630    #[test]
1631    fn test_use_wildcard_transpiles() {
1632        let r_code = FluentParser::new()
1633            .push("module Math { @pub let pi <- 3; @pub let e <- 2; let secret <- 0; };")
1634            .push("use Math::*;")
1635            .run()
1636            .run()
1637            .get_r_code()
1638            .iter()
1639            .cloned()
1640            .collect::<Vec<_>>()
1641            .join("\n");
1642        assert!(
1643            r_code.contains("pi <- Math$pi"),
1644            "missing pi binding: {}",
1645            r_code
1646        );
1647        assert!(
1648            r_code.contains("e <- Math$e"),
1649            "missing e binding: {}",
1650            r_code
1651        );
1652        assert!(
1653            !r_code.contains("secret <- Math$secret"),
1654            "private member must not be imported: {}",
1655            r_code
1656        );
1657    }
1658
1659    #[test]
1660    fn test_array_constructor_call_transpilation() {
1661        let r_code = FluentParser::new()
1662            .push("type Bits <- [Any, int];")
1663            .run()
1664            .push("let b <- Bits:[1, 2, 3];")
1665            .run()
1666            .get_r_code()
1667            .iter()
1668            .cloned()
1669            .collect::<Vec<_>>()
1670            .join("\n");
1671        assert!(
1672            r_code.contains("Bits(typed_vec("),
1673            "expected Bits(...) constructor: {}",
1674            r_code
1675        );
1676        assert!(
1677            r_code.contains("dim = c(3)"),
1678            "expected dimension annotation: {}",
1679            r_code
1680        );
1681    }
1682
1683    #[test]
1684    fn test_record_alias_return_no_constructor_pipe() {
1685        // A function returning a record alias must NOT get `|> TypeName()` in
1686        // its body — the constructor takes specific named fields, not a single
1687        // value, so piping the body result through it would fail at runtime.
1688        let r_code = FluentParser::new()
1689            .push("type Point <- list { x: int, y: int };")
1690            .run()
1691            .push("let incr <- fn(p: Point): Point { Point:{x: (p$x+1), y: (p$y+1)} };")
1692            .run()
1693            .get_r_code()
1694            .iter()
1695            .cloned()
1696            .collect::<Vec<_>>()
1697            .join("\n");
1698        // The method definition must not contain `|> Point()` inside the body
1699        assert!(
1700            !r_code.contains("}) |> Point()"),
1701            "record alias output conversion should not be added: {}",
1702            r_code
1703        );
1704        // The method should still be wrapped by Generic() for S3 dispatch
1705        assert!(
1706            r_code.contains("|> Generic()") || r_code.contains("|> Function"),
1707            "function type annotation should still be applied: {}",
1708            r_code
1709        );
1710    }
1711
1712    #[test]
1713    fn test_alias_int_generates_validator() {
1714        let r_code = FluentParser::new()
1715            .check_transpiling("type Meters <- int;");
1716        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1717        assert!(
1718            r_str.contains(".validate_Meters <- function(x)"),
1719            "expected validator function, got: {}",
1720            r_str
1721        );
1722        assert!(
1723            r_str.contains("is.integer"),
1724            "expected is.integer check, got: {}",
1725            r_str
1726        );
1727    }
1728
1729    #[test]
1730    fn test_alias_char_generates_validator() {
1731        let r_code = FluentParser::new()
1732            .check_transpiling("type Name <- char;");
1733        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1734        assert!(
1735            r_str.contains(".validate_Name <- function(x)"),
1736            "expected validator function, got: {}",
1737            r_str
1738        );
1739        assert!(
1740            r_str.contains("is.character"),
1741            "expected is.character check, got: {}",
1742            r_str
1743        );
1744    }
1745
1746    #[test]
1747    fn test_alias_bool_generates_validator() {
1748        let r_code = FluentParser::new()
1749            .check_transpiling("type Flag <- bool;");
1750        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1751        assert!(
1752            r_str.contains(".validate_Flag <- function(x)"),
1753            "expected validator function, got: {}",
1754            r_str
1755        );
1756        assert!(
1757            r_str.contains("is.logical"),
1758            "expected is.logical check, got: {}",
1759            r_str
1760        );
1761    }
1762
1763    #[test]
1764    fn test_alias_num_generates_validator() {
1765        let r_code = FluentParser::new()
1766            .check_transpiling("type Real <- num;");
1767        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1768        assert!(
1769            r_str.contains(".validate_Real <- function(x)"),
1770            "expected validator function, got: {}",
1771            r_str
1772        );
1773        assert!(
1774            r_str.contains("is.numeric"),
1775            "expected is.numeric check, got: {}",
1776            r_str
1777        );
1778    }
1779
1780    #[test]
1781    fn test_validating_cast_int() {
1782        let r_code = FluentParser::new()
1783            .push("type Meters <- int;")
1784            .run()
1785            .check_transpiling("x as! Meters");
1786        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1787        assert!(
1788            r_str.contains(".validate_Meters(x)"),
1789            "expected .validate_Meters(x), got: {}",
1790            r_str
1791        );
1792    }
1793
1794    #[test]
1795    fn test_tag_alias_char_generates_validator() {
1796        let r_code = FluentParser::new()
1797            .check_transpiling("type Hello <- .Hello(char);");
1798        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1799        assert!(
1800            r_str.contains(".validate_Hello <- function(x)"),
1801            "expected validator function, got: {}",
1802            r_str
1803        );
1804        assert!(
1805            r_str.contains("x[[1]] != 'Hello'"),
1806            "expected tag name check, got: {}",
1807            r_str
1808        );
1809        assert!(
1810            r_str.contains("x[[\"body\"]]"),
1811            "expected body field check, got: {}",
1812            r_str
1813        );
1814        assert!(
1815            r_str.contains("is.character"),
1816            "expected is.character check on body, got: {}",
1817            r_str
1818        );
1819    }
1820
1821    #[test]
1822    fn test_tag_alias_int_generates_validator() {
1823        let r_code = FluentParser::new()
1824            .check_transpiling("type Count <- .Count(int);");
1825        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1826        assert!(
1827            r_str.contains(".validate_Count <- function(x)"),
1828            "expected validator, got: {}",
1829            r_str
1830        );
1831        assert!(
1832            r_str.contains("x[[1]] != 'Count'"),
1833            "expected tag name check, got: {}",
1834            r_str
1835        );
1836        assert!(
1837            r_str.contains("is.integer"),
1838            "expected is.integer check on body, got: {}",
1839            r_str
1840        );
1841    }
1842
1843    #[test]
1844    fn test_tag_alias_with_alias_body_calls_nested_validator() {
1845        let r_code = FluentParser::new()
1846            .push("type Name <- char;")
1847            .run()
1848            .check_transpiling("type Tagged <- .Tagged(Name);");
1849        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1850        assert!(
1851            r_str.contains(".validate_Tagged <- function(x)"),
1852            "expected validator, got: {}",
1853            r_str
1854        );
1855        assert!(
1856            r_str.contains(".validate_Name(x[[\"body\"]])"),
1857            "expected nested validator call, got: {}",
1858            r_str
1859        );
1860    }
1861
1862    #[test]
1863    fn test_literal_char_alias_generates_exact_validator() {
1864        let r_code = FluentParser::new()
1865            .check_transpiling("type Hello <- \"hello\";");
1866        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1867        assert!(
1868            r_str.contains(".validate_Hello <- function(x)"),
1869            "expected validator function, got: {}",
1870            r_str
1871        );
1872        assert!(
1873            r_str.contains("x != 'hello'"),
1874            "expected literal equality check, got: {}",
1875            r_str
1876        );
1877    }
1878
1879    #[test]
1880    fn test_literal_int_alias_generates_exact_validator() {
1881        let r_code = FluentParser::new()
1882            .check_transpiling("type Byte <- 89;");
1883        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1884        assert!(
1885            r_str.contains(".validate_Byte <- function(x)"),
1886            "expected validator function, got: {}",
1887            r_str
1888        );
1889        assert!(
1890            r_str.contains("x != 89L"),
1891            "expected literal equality check, got: {}",
1892            r_str
1893        );
1894    }
1895
1896    #[test]
1897    fn test_literal_num_alias_generates_exact_validator() {
1898        let r_code = FluentParser::new()
1899            .check_transpiling("type Pi <- 3.14;");
1900        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1901        assert!(
1902            r_str.contains(".validate_Pi <- function(x)"),
1903            "expected validator function, got: {}",
1904            r_str
1905        );
1906        assert!(
1907            r_str.contains("x != 3.14"),
1908            "expected literal equality check, got: {}",
1909            r_str
1910        );
1911    }
1912
1913    #[test]
1914    fn test_literal_bool_true_alias_generates_exact_validator() {
1915        let r_code = FluentParser::new()
1916            .check_transpiling("type Yes <- true;");
1917        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1918        assert!(
1919            r_str.contains(".validate_Yes <- function(x)"),
1920            "expected validator function, got: {}",
1921            r_str
1922        );
1923        assert!(
1924            r_str.contains("x != TRUE"),
1925            "expected literal TRUE check, got: {}",
1926            r_str
1927        );
1928    }
1929
1930    #[test]
1931    fn test_literal_bool_false_alias_generates_exact_validator() {
1932        let r_code = FluentParser::new()
1933            .check_transpiling("type No <- false;");
1934        let r_str = r_code.iter().cloned().collect::<Vec<_>>().join("\n");
1935        assert!(
1936            r_str.contains(".validate_No <- function(x)"),
1937            "expected validator function, got: {}",
1938            r_str
1939        );
1940        assert!(
1941            r_str.contains("x != FALSE"),
1942            "expected literal FALSE check, got: {}",
1943            r_str
1944        );
1945    }
1946}