Skip to main content

typr_core/processes/parsing/
mod.rs

1#![allow(dead_code)]
2
3pub mod elements;
4pub mod indexation;
5pub mod lang_token;
6pub mod operation_priority;
7pub mod type_token;
8pub mod types;
9pub mod vector_priority;
10
11use crate::components::context::config::Config;
12use crate::components::error_message::help_data::HelpData;
13use crate::components::error_message::syntax_error::SyntaxError;
14use crate::components::language::operators::custom_op;
15use crate::components::language::operators::Op;
16use crate::components::language::var::Var;
17use crate::components::language::Lang;
18use crate::components::language::ModulePosition;
19use crate::components::r#type::vector_type::ConstructorCategory;
20use crate::components::r#type::Type;
21use crate::processes::parsing::elements::break_exp;
22use crate::processes::parsing::elements::chars;
23use crate::processes::parsing::elements::next_exp;
24use crate::processes::parsing::elements::parse_elements;
25use crate::processes::parsing::elements::return_exp;
26use crate::processes::parsing::elements::scope;
27use crate::processes::parsing::elements::single_element;
28use crate::processes::parsing::elements::tag_exp;
29use crate::processes::parsing::elements::tuple_exp;
30use crate::processes::parsing::elements::variable;
31use crate::processes::parsing::elements::variable2;
32use crate::processes::parsing::elements::variable_exp;
33use crate::processes::parsing::elements::variable_recognizer;
34use crate::processes::parsing::elements::vector;
35use crate::processes::parsing::elements::Case;
36use crate::processes::parsing::types::ltype;
37use crate::processes::parsing::types::pascal_case_no_space;
38use crate::processes::parsing::types::type_alias;
39use nom::branch::alt;
40use nom::bytes::complete::tag;
41use nom::character::complete::line_ending;
42use nom::character::complete::multispace0;
43use nom::character::complete::not_line_ending;
44use nom::combinator::map;
45use nom::combinator::opt;
46use nom::multi::many0;
47use nom::multi::separated_list0;
48use nom::sequence::delimited;
49use nom::sequence::pair;
50use nom::sequence::preceded;
51use nom::sequence::terminated;
52use nom::IResult;
53use nom::Parser;
54use nom_locate::LocatedSpan;
55use std::ops::Deref;
56
57type Span<'a> = LocatedSpan<&'a str, String>;
58
59use std::cell::RefCell;
60
61thread_local! {
62    static PARSE_ERRORS: RefCell<Vec<SyntaxError>> = const { RefCell::new(Vec::new()) };
63}
64
65fn push_parse_error(err: SyntaxError) {
66    PARSE_ERRORS.with(|e| e.borrow_mut().push(err));
67}
68
69fn take_parse_errors() -> Vec<SyntaxError> {
70    PARSE_ERRORS.with(|e| e.borrow_mut().drain(..).collect())
71}
72
73/// Result of parsing containing the AST and any syntax errors collected
74#[derive(Debug, Clone)]
75pub struct ParseResult {
76    pub ast: Lang,
77    pub errors: Vec<SyntaxError>,
78}
79
80impl ParseResult {
81    pub fn new(ast: Lang) -> Self {
82        let errors = take_parse_errors();
83        ParseResult { ast, errors }
84    }
85
86    pub fn has_errors(&self) -> bool {
87        !self.errors.is_empty()
88    }
89
90    pub fn get_ast(&self) -> &Lang {
91        &self.ast
92    }
93
94    pub fn get_clean_ast(&self) -> Lang {
95        self.ast.clone()
96    }
97}
98
99fn pattern_var(s: Span) -> IResult<Span, (Vec<Lang>, Option<String>)> {
100    let res = alt((tag_exp, variable2)).parse(s);
101    match res {
102        Ok((
103            s,
104            Lang::Tag {
105                name, value: val, ..
106            },
107        )) => {
108            if let Lang::Variable {
109                name: name2,
110                is_opaque: mutopa,
111                related_type: typ,
112                help_data: h,
113            } = *val
114            {
115                Ok((
116                    s,
117                    (
118                        vec![Lang::Variable {
119                            name: name2.to_string(),
120                            is_opaque: mutopa,
121                            related_type: typ,
122                            help_data: h.clone(),
123                        }],
124                        Some(name.to_string()),
125                    ),
126                ))
127            } else {
128                Ok((s, (vec![], Some(name.to_string()))))
129            }
130        }
131        Ok((
132            s,
133            Lang::Variable {
134                name,
135                is_opaque: mutopa,
136                related_type: typ,
137                help_data: h,
138            },
139        )) => Ok((
140            s,
141            (
142                vec![Lang::Variable {
143                    name,
144                    is_opaque: mutopa,
145                    related_type: typ,
146                    help_data: h.clone(),
147                }],
148                None,
149            ),
150        )),
151        Err(r) => Err(r),
152        _ => todo!(),
153    }
154}
155
156fn single_parse(s: Span) -> IResult<Span, Lang> {
157    let res = (parse_elements, opt(terminated(tag(";"), multispace0))).parse(s);
158    match res {
159        Ok((s, (exp, Some(_)))) => Ok((s, exp)),
160        Ok((s, (exp, None))) => {
161            push_parse_error(SyntaxError::ForgottenSemicolon(exp.clone().into()));
162            Ok((s, exp))
163        }
164        Err(r) => Err(r),
165    }
166}
167
168fn equality_operator(s: Span) -> IResult<Span, Span> {
169    terminated(alt((tag("="), tag("<-"))), multispace0).parse(s)
170}
171
172fn base_let_exp(s: Span) -> IResult<Span, Vec<Lang>> {
173    let res = (
174        terminated(tag("let"), multispace0),
175        pattern_var,
176        opt(preceded(terminated(tag(":"), multispace0), ltype)),
177        equality_operator,
178        single_parse,
179    )
180        .parse(s);
181    match res {
182        Ok((
183            s,
184            (
185                _let,
186                (pat_var, None),
187                typ,
188                _eq,
189                Lang::Function {
190                    parameters: params,
191                    return_type: ty,
192                    body,
193                    help_data: h,
194                },
195            ),
196        )) if !params.is_empty() => {
197            let newvar = Var::from_language(pat_var[0].clone())
198                .unwrap()
199                .set_type(params[0].1.clone());
200            if let Lang::Variable {
201                name, help_data, ..
202            } = &pat_var[0]
203            {
204                if name.chars().next().is_some_and(|c| c.is_uppercase()) {
205                    push_parse_error(SyntaxError::LetInsteadOfType {
206                        name: name.clone(),
207                        help_data: help_data.clone(),
208                    });
209                }
210            }
211            Ok((
212                s,
213                vec![Lang::Let {
214                    variable: Box::new(newvar.to_language()),
215                    r#type: typ.unwrap_or(Type::Empty(HelpData::default())),
216                    expression: Box::new(Lang::Function {
217                        parameters: params,
218                        return_type: ty,
219                        body,
220                        help_data: h,
221                    }),
222                    is_public: false,
223                    is_testable: false,
224                    is_export: false,
225                    help_data: _let.into(),
226                }],
227            ))
228        }
229        Ok((s, (_let, (pat_var, None), typ, _eq, body))) => {
230            if let Lang::Variable {
231                name, help_data, ..
232            } = &pat_var[0]
233            {
234                if name.chars().next().is_some_and(|c| c.is_uppercase()) {
235                    push_parse_error(SyntaxError::LetInsteadOfType {
236                        name: name.clone(),
237                        help_data: help_data.clone(),
238                    });
239                }
240            }
241            Ok((
242                s,
243                vec![Lang::Let {
244                    variable: Box::new(pat_var[0].clone()),
245                    r#type: typ.clone().unwrap_or(Type::Empty(HelpData::default())),
246                    expression: Box::new(body),
247                    is_public: false,
248                    is_testable: false,
249                    is_export: false,
250                    help_data: _let.into(),
251                }],
252            ))
253        }
254        Ok((s, (_let, (pat_var, Some(_)), typ, eq, body))) => {
255            if pat_var.len() == 1 {
256                Ok((
257                    s,
258                    vec![Lang::Let {
259                        variable: Box::new(pat_var[0].clone()),
260                        r#type: typ.clone().unwrap_or(Type::Empty(HelpData::default())),
261                        expression: Box::new(Lang::Operator {
262                            operator: Op::Dollar(HelpData::default()),
263                            rhs: Box::new(Lang::Number {
264                                value: 0.0,
265                                help_data: eq.into(),
266                            }),
267                            lhs: Box::new(body),
268                            help_data: pat_var.into(),
269                        }),
270                        is_public: false,
271                        is_testable: false,
272                        is_export: false,
273                        help_data: _let.into(),
274                    }],
275                ))
276            } else {
277                Ok((
278                    s,
279                    pat_var
280                        .iter()
281                        .map(|x| Lang::Let {
282                            variable: Box::new(x.clone()),
283                            r#type: typ.clone().unwrap_or(Type::Empty(HelpData::default())),
284                            expression: Box::new(body.clone()),
285                            is_public: false,
286                            is_testable: false,
287                            is_export: false,
288                            help_data: HelpData::default(),
289                        })
290                        .collect::<Vec<_>>(),
291                ))
292            }
293        }
294        Err(r) => Err(r),
295    }
296}
297
298fn let_tuple_exp(s: Span) -> IResult<Span, Vec<Lang>> {
299    let res = (
300        terminated(tag("let"), multispace0),
301        tuple_exp,
302        opt(preceded(terminated(tag(":"), multispace0), ltype)),
303        equality_operator,
304        single_parse,
305    )
306        .parse(s);
307    match res {
308        Ok((
309            s,
310            (
311                _let,
312                Lang::Tuple {
313                    value: elements,
314                    help_data: _th,
315                },
316                typ,
317                _eq,
318                body,
319            ),
320        )) => {
321            let tmp_name = "__tuple_tmp__";
322            let tmp_var = Var::from_name(tmp_name).to_language();
323
324            // First: let __tuple_tmp__ <- body;
325            let tmp_let = Lang::Let {
326                variable: Box::new(tmp_var.clone()),
327                r#type: typ.unwrap_or(Type::Empty(HelpData::default())),
328                expression: Box::new(body),
329                is_public: false,
330                is_testable: false,
331                is_export: false,
332                help_data: _let.into(),
333            };
334
335            // Then: let a <- 1.__tuple_tmp__; let b <- 2.__tuple_tmp__; ...
336            let mut result = vec![tmp_let];
337            for (i, elem) in elements.iter().enumerate() {
338                if let Lang::Variable { name, .. } = elem {
339                    if name == "_" {
340                        continue; // skip wildcard
341                    }
342                }
343                result.push(Lang::Let {
344                    variable: Box::new(elem.clone()),
345                    r#type: Type::Empty(HelpData::default()),
346                    expression: Box::new(Lang::Operator {
347                        operator: Op::Dot(HelpData::default()),
348                        rhs: Box::new(Lang::Integer {
349                            value: (i + 1) as i32,
350                            help_data: HelpData::default(),
351                        }),
352                        lhs: Box::new(tmp_var.clone()),
353                        help_data: HelpData::default(),
354                    }),
355                    is_public: false,
356                    is_testable: false,
357                    is_export: false,
358                    help_data: HelpData::default(),
359                });
360            }
361
362            Ok((s, result))
363        }
364        Ok(_) => unreachable!("tuple_exp always returns Lang::Tuple"),
365        Err(r) => Err(r),
366    }
367}
368
369fn let_exp(s: Span) -> IResult<Span, Vec<Lang>> {
370    let res = (
371        opt(terminated(
372            alt((tag("@export"), tag("@pub"), tag("@testable"))),
373            multispace0,
374        )),
375        base_let_exp,
376    )
377        .parse(s);
378    match res {
379        Ok((s, (None, le))) => Ok((s, le)),
380        Ok((s, (Some(annotation), le))) => {
381            // `@export` → public + testable + exported in R package (RFC-TR-032).
382            // `@pub`    → public + testable (RFC-TR-032, §3.2).
383            // `@testable` → private but exposed as `M$.test_<name>` in test builds.
384            let frag = *annotation.fragment();
385            let is_pub = frag == "@pub" || frag == "@export";
386            let is_test = frag == "@testable" || frag == "@pub" || frag == "@export";
387            let is_exp = frag == "@export";
388            let new_le = le
389                .iter()
390                .map(|x| match x {
391                    Lang::Let {
392                        variable: var,
393                        r#type: typ,
394                        expression: body,
395                        is_public: _,
396                        is_testable: _,
397                        is_export: _,
398                        help_data: h,
399                    } => {
400                        let vari = Var::from_language(var.deref().clone())
401                            .unwrap()
402                            .to_language();
403                        Lang::Let {
404                            variable: Box::new(vari),
405                            r#type: typ.clone(),
406                            expression: body.clone(),
407                            is_public: is_pub,
408                            is_testable: is_test,
409                            is_export: is_exp,
410                            help_data: h.clone(),
411                        }
412                    }
413                    lan => lan.clone(),
414                })
415                .collect();
416            Ok((s, new_le))
417        }
418        Err(r) => Err(r),
419    }
420}
421
422/// Parses a `typeconstructor` declaration that registers a new type constructor:
423///   `typeconstructor Tibble[N] record;`
424///   `typeconstructor Matrix[N, M, T] recursive;`
425fn typeconstructor_exp(s: Span) -> IResult<Span, Vec<Lang>> {
426    let res = (
427        terminated(tag("typeconstructor"), multispace0),
428        pascal_case_no_space,
429        delimited(
430            terminated(tag("["), multispace0),
431            separated_list0(
432                terminated(tag(","), multispace0),
433                terminated(ltype, multispace0),
434            ),
435            terminated(tag("]"), multispace0),
436        ),
437        terminated(alt((tag("recursive"), tag("record"))), multispace0),
438        terminated(tag(";"), multispace0),
439    )
440        .parse(s);
441    match res {
442        Ok((s, (_kw, (name, h), params, category, _semi))) => {
443            let category = match *category.fragment() {
444                "recursive" => ConstructorCategory::Recursive,
445                _ => ConstructorCategory::Record,
446            };
447            Ok((
448                s,
449                vec![Lang::TypeConstructor {
450                    name,
451                    parameters: params,
452                    category,
453                    help_data: h,
454                }],
455            ))
456        }
457        Err(r) => Err(r),
458    }
459}
460
461fn base_type_exp(s: Span) -> IResult<Span, Lang> {
462    let res = (
463        terminated(tag("type"), multispace0),
464        type_alias,
465        equality_operator,
466        ltype,
467        terminated(tag(";"), multispace0),
468    )
469        .parse(s);
470    match res {
471        Ok((s, (_ty, Type::Alias(name, params, _, h), _eq, ty, _))) => {
472            let h2 = if !params.is_empty() {
473                params[0].clone().into()
474            } else {
475                HelpData::default()
476            };
477            let vari = Var::from_name(&name)
478                .set_type(Type::Params(params.clone(), h2))
479                .to_language();
480            Ok((
481                s,
482                Lang::Alias {
483                    identifier: Box::new(vari),
484                    parameters: params,
485                    target_type: ty,
486                    is_public: false,
487                    help_data: h,
488                },
489            ))
490        }
491        Ok((s, (_ty, _, _eq, _ty2, _))) => Ok((s, Lang::Empty(_ty.into()))),
492        Err(r) => Err(r),
493    }
494}
495
496fn type_exp(s: Span) -> IResult<Span, Vec<Lang>> {
497    let res = (opt(terminated(tag("@pub"), multispace0)), base_type_exp).parse(s);
498    match res {
499        Ok((
500            s,
501            (
502                Some(_pu),
503                Lang::Alias {
504                    identifier: var,
505                    parameters: params,
506                    target_type: typ,
507                    help_data: h,
508                    ..
509                },
510            ),
511        )) => Ok((
512            s,
513            vec![Lang::Alias {
514                identifier: var,
515                parameters: params,
516                target_type: typ,
517                is_public: true,
518                help_data: h,
519            }],
520        )),
521        Ok((
522            s,
523            (
524                None,
525                Lang::Alias {
526                    identifier: var,
527                    parameters: params,
528                    target_type: typ,
529                    help_data: h,
530                    ..
531                },
532            ),
533        )) => {
534            let vari = Var::from_language(var.deref().clone())
535                .unwrap()
536                .to_language();
537            Ok((
538                s,
539                vec![Lang::Alias {
540                    identifier: Box::new(vari),
541                    parameters: params,
542                    target_type: typ,
543                    is_public: false,
544                    help_data: h,
545                }],
546            ))
547        }
548        Err(r) => Err(r),
549        _ => todo!(),
550    }
551}
552
553/// Detects `type <lowercase_var> <- <expr>` which should be `let` instead.
554/// Parses the full expression and returns a `Lang::Let` with a push_parse_error.
555fn type_instead_of_let_exp(s: Span) -> IResult<Span, Vec<Lang>> {
556    let res = (
557        opt(terminated(tag("@pub"), multispace0)),
558        terminated(tag("type"), multispace0),
559        terminated(variable_exp, multispace0),
560        equality_operator,
561        single_parse,
562    )
563        .parse(s);
564    match res {
565        Ok((s, (pub_ann, type_kw, (name, h), _eq, body))) => {
566            push_parse_error(SyntaxError::TypeInsteadOfLet {
567                name: name.clone(),
568                help_data: h.clone(),
569            });
570            let is_pub = pub_ann.is_some();
571            Ok((
572                s,
573                vec![Lang::Let {
574                    variable: Box::new(Lang::Variable {
575                        name,
576                        is_opaque: false,
577                        related_type: Type::Empty(HelpData::default()),
578                        help_data: h,
579                    }),
580                    r#type: Type::Empty(type_kw.clone().into()),
581                    expression: Box::new(body),
582                    is_public: is_pub,
583                    is_testable: is_pub,
584                    is_export: false,
585                    help_data: type_kw.into(),
586                }],
587            ))
588        }
589        Err(r) => Err(r),
590    }
591}
592
593fn base_opaque_exp(s: Span) -> IResult<Span, Lang> {
594    let res = (
595        terminated(tag("opaque"), multispace0),
596        type_alias,
597        equality_operator,
598        ltype,
599        terminated(tag(";"), multispace0),
600    )
601        .parse(s);
602    match res {
603        Ok((s, (_ty, Type::Alias(name, params, _, h), _eq, ty, _))) => {
604            let vari = Var::from_name(&name)
605                .set_type(Type::Params(params.clone(), params.clone().into()))
606                .set_opacity(true)
607                .to_language();
608            Ok((
609                s,
610                Lang::Alias {
611                    identifier: Box::new(vari),
612                    parameters: params,
613                    target_type: ty,
614                    is_public: false,
615                    help_data: h,
616                },
617            ))
618        }
619        Ok((s, (_ty, _, _eq, _ty2, _))) => Ok((s, Lang::Empty(_ty.into()))),
620        Err(r) => Err(r),
621    }
622}
623
624fn opaque_exp(s: Span) -> IResult<Span, Vec<Lang>> {
625    let res = (opt(terminated(tag("@pub"), multispace0)), base_opaque_exp).parse(s);
626    match res {
627        Ok((
628            s,
629            (
630                Some(_pu),
631                Lang::Alias {
632                    identifier: var,
633                    parameters: params,
634                    target_type: typ,
635                    help_data: h,
636                    ..
637                },
638            ),
639        )) => {
640            let vari = Var::from_language(var.deref().clone())
641                .unwrap()
642                .set_opacity(true)
643                .to_language();
644            Ok((
645                s,
646                vec![Lang::Alias {
647                    identifier: Box::new(vari),
648                    parameters: params,
649                    target_type: typ,
650                    is_public: true,
651                    help_data: h,
652                }],
653            ))
654        }
655        Ok((
656            s,
657            (
658                None,
659                Lang::Alias {
660                    identifier: var,
661                    parameters: params,
662                    target_type: typ,
663                    help_data: h,
664                    ..
665                },
666            ),
667        )) => {
668            let vari = Var::from_language(var.deref().clone())
669                .unwrap()
670                .set_opacity(true)
671                .to_language();
672            Ok((
673                s,
674                vec![Lang::Alias {
675                    identifier: Box::new(vari),
676                    parameters: params,
677                    target_type: typ,
678                    is_public: false,
679                    help_data: h,
680                }],
681            ))
682        }
683        Err(r) => Err(r),
684        _ => todo!(),
685    }
686}
687
688pub fn module(s: Span) -> IResult<Span, Vec<Lang>> {
689    let res = (
690        terminated(tag("module"), multispace0),
691        terminated(variable_recognizer, multispace0),
692        terminated(tag("{"), multispace0),
693        base_parse,
694        terminated(tag("}"), multispace0),
695        opt(terminated(tag(";"), multispace0)),
696    )
697        .parse(s);
698    match res {
699        Ok((s, (modu, (name, _), _op, v, _cl, _dv))) => Ok((
700            s,
701            vec![Lang::Module {
702                name,
703                body: v,
704                module_position: ModulePosition::Internal,
705                config: Config::default(),
706                help_data: modu.into(),
707            }],
708        )),
709        Err(r) => Err(r),
710    }
711}
712
713fn import_module(s: Span) -> IResult<Span, Vec<Lang>> {
714    let res = (
715        terminated(tag("import"), multispace0),
716        terminated(variable_recognizer, multispace0),
717        opt((
718            terminated(tag("as"), multispace0),
719            terminated(variable_recognizer, multispace0),
720        )),
721        opt(terminated(tag(";"), multispace0)),
722    )
723        .parse(s);
724    match res {
725        Ok((s, (import_kw, (name, _), None, _))) => Ok((
726            s,
727            vec![Lang::ModuleImport {
728                value: name,
729                help_data: import_kw.into(),
730            }],
731        )),
732        Ok((s, (_, (name, h), Some((_, (alias, _))), _))) => {
733            let module_var = Lang::Variable {
734                name,
735                is_opaque: false,
736                related_type: Type::Empty(HelpData::default()),
737                help_data: h.clone(),
738            };
739            let alias_var = Var::from_name(&alias).to_language();
740            Ok((
741                s,
742                vec![Lang::Let {
743                    variable: Box::new(alias_var),
744                    r#type: Type::Empty(HelpData::default()),
745                    expression: Box::new(module_var),
746                    is_public: false,
747                    is_testable: false,
748                    is_export: false,
749                    help_data: h,
750                }],
751            ))
752        }
753        Err(r) => Err(r),
754    }
755}
756
757fn assign(s: Span) -> IResult<Span, Vec<Lang>> {
758    let res = (
759        variable,
760        alt((
761            terminated(tag("="), multispace0),
762            terminated(tag("<-"), multispace0),
763        )),
764        parse_elements,
765        opt(terminated(tag(";"), multispace0)),
766    )
767        .parse(s);
768    match res {
769        Ok((s, ((var, _), _eq, exp, Some(_)))) => Ok((
770            s,
771            vec![Lang::Assign {
772                identifier: Box::new(var.clone()),
773                expression: Box::new(exp),
774                help_data: var.into(),
775            }],
776        )),
777        Ok((s, ((var, _), _eq, exp, None))) => {
778            push_parse_error(SyntaxError::ForgottenSemicolon(exp.clone().into()));
779            let assign = Lang::Assign {
780                identifier: Box::new(var.clone()),
781                expression: Box::new(exp),
782                help_data: var.into(),
783            };
784            Ok((s, vec![assign]))
785        }
786        Err(r) => Err(r),
787    }
788}
789
790fn comment(s: Span) -> IResult<Span, Vec<Lang>> {
791    let res = (tag("#"), not_line_ending, opt(line_ending), multispace0).parse(s);
792    match res {
793        Ok((s, (_hashtag, txt, _, _))) => Ok((
794            s,
795            vec![Lang::Comment {
796                value: txt.to_string(),
797                help_data: _hashtag.into(),
798            }],
799        )),
800        Err(r) => Err(r),
801    }
802}
803
804pub fn simple_exp(s: Span) -> IResult<Span, Vec<Lang>> {
805    let res = (parse_elements, opt(terminated(tag(";"), multispace0))).parse(s);
806    match res {
807        Ok((s, (lang, Some(_)))) => Ok((s, vec![lang])),
808        Ok((s, (lang, None))) => {
809            push_parse_error(SyntaxError::ForgottenSemicolon(lang.clone().into()));
810            Ok((s, vec![lang]))
811        }
812        Err(r) => Err(r),
813    }
814}
815
816fn mod_imp(s: Span) -> IResult<Span, Vec<Lang>> {
817    let res = (
818        terminated(tag("mod"), multispace0),
819        terminated(variable_exp, multispace0),
820        terminated(tag(";"), multispace0),
821    )
822        .parse(s);
823    match res {
824        Ok((s, (_mod, (name, _), _sc))) => Ok((
825            s,
826            vec![Lang::ModuleImport {
827                value: name.to_string(),
828                help_data: _mod.into(),
829            }],
830        )),
831        Err(r) => Err(r),
832    }
833}
834
835fn import_var(s: Span) -> IResult<Span, Vec<Lang>> {
836    let res = (
837        terminated(tag("use"), multispace0),
838        variable,
839        terminated(tag(";"), multispace0),
840    )
841        .parse(s);
842    match res {
843        Ok((s, (_use, (lang, case), _sc))) => {
844            let res = match case {
845                Case::Maj => Var::from_language(lang).unwrap().to_alias_lang(),
846                _ => Var::from_language(lang).unwrap().to_let(),
847            };
848            Ok((s, vec![res]))
849        }
850        Err(r) => Err(r),
851    }
852}
853
854fn import_type(s: Span) -> IResult<Span, Vec<Lang>> {
855    let res = (
856        terminated(tag("use"), multispace0),
857        type_alias,
858        terminated(tag(";"), multispace0),
859    )
860        .parse(s);
861
862    match res {
863        Ok((s, (_use, alias, _sc))) => Ok((
864            s,
865            vec![Lang::Import {
866                value: alias,
867                help_data: _use.into(),
868            }],
869        )),
870        Err(r) => Err(r),
871    }
872}
873
874fn tests(s: Span) -> IResult<Span, Vec<Lang>> {
875    let res = (tag("Test"), delimited(tag("["), base_parse, tag("]"))).parse(s);
876    match res {
877        Ok((s, (_t, body))) => Ok((
878            s,
879            vec![Lang::Test {
880                value: body,
881                help_data: _t.into(),
882            }],
883        )),
884        Err(r) => Err(r),
885    }
886}
887
888fn library(s: Span) -> IResult<Span, Vec<Lang>> {
889    let res = (
890        tag("library("),
891        variable_exp,
892        tag(")"),
893        opt(tag(";")),
894        multispace0,
895    )
896        .parse(s);
897
898    match res {
899        Ok((s, (_lib, (var, h), _cl, Some(_col), _))) => Ok((
900            s,
901            vec![Lang::Library {
902                value: var,
903                help_data: h.clone(),
904            }],
905        )),
906        Ok((_, (_lib, _var, _cl, None, _))) => {
907            panic!("You forgot to put a ';' at the end of the line")
908        }
909        Err(r) => Err(r),
910    }
911}
912
913fn use_item_exp(s: Span) -> IResult<Span, crate::components::language::use_lang::UseItem> {
914    use crate::components::language::use_lang::UseItem;
915    // Parse: Ident (as Ident)?
916    let res = (
917        terminated(variable_recognizer, multispace0),
918        opt(preceded(
919            pair(tag("as"), multispace0),
920            terminated(variable_recognizer, multispace0),
921        )),
922    )
923        .parse(s);
924    match res {
925        Ok((s, ((name, _), alias_opt))) => {
926            let alias = alias_opt.map(|(alias_name, _)| alias_name);
927            Ok((s, UseItem { name, alias }))
928        }
929        Err(r) => Err(r),
930    }
931}
932
933fn use_items_selector(
934    s: Span,
935) -> IResult<Span, crate::components::language::use_lang::UseSelector> {
936    use crate::components::language::use_lang::UseSelector;
937    let res = (
938        pair(tag("{"), multispace0),
939        separated_list0(pair(tag(","), multispace0), use_item_exp),
940        opt(pair(tag(","), multispace0)),
941        pair(tag("}"), multispace0),
942    )
943        .parse(s);
944    match res {
945        Ok((s, (_, items, _, _))) => Ok((s, UseSelector::Items(items))),
946        Err(r) => Err(r),
947    }
948}
949
950fn use_selector_exp(s: Span) -> IResult<Span, crate::components::language::use_lang::UseSelector> {
951    use crate::components::language::use_lang::UseSelector;
952    alt((
953        map(terminated(tag("*"), multispace0), |_| UseSelector::Wildcard),
954        use_items_selector,
955    ))
956    .parse(s)
957}
958
959fn use_module_directive(s: Span) -> IResult<Span, Vec<Lang>> {
960    use crate::components::language::use_lang::UseSelector;
961
962    // Parse: use FirstSeg :: ...
963    let res = (
964        terminated(tag("use"), multispace0),
965        terminated(variable_recognizer, multispace0),
966        pair(tag("::"), multispace0),
967    )
968        .parse(s);
969
970    let (s, (use_kw, (first_seg, _), _)) = res?;
971
972    let mut path = vec![first_seg];
973    let mut current_s = s;
974    let selector;
975
976    loop {
977        match use_selector_exp(current_s.clone()) {
978            Ok((s2, sel)) => {
979                selector = sel;
980                current_s = s2;
981                break;
982            }
983            Err(_) => match terminated(variable_recognizer, multispace0).parse(current_s.clone()) {
984                Ok((s2, (seg, _))) => {
985                    let colon_res: IResult<Span, (Span, Span)> =
986                        pair(tag("::"), multispace0).parse(s2.clone());
987                    match colon_res {
988                        Ok((s3, _)) => {
989                            path.push(seg);
990                            current_s = s3;
991                        }
992                        Err(_) => {
993                            use crate::components::language::use_lang::UseItem;
994                            selector = UseSelector::Items(vec![UseItem {
995                                name: seg,
996                                alias: None,
997                            }]);
998                            current_s = s2;
999                            break;
1000                        }
1001                    }
1002                }
1003                Err(e) => return Err(e),
1004            },
1005        }
1006    }
1007
1008    let res = terminated(tag(";"), multispace0).parse(current_s);
1009    let (s, _) = res?;
1010
1011    Ok((
1012        s,
1013        vec![Lang::UseModule {
1014            module_path: path,
1015            selector,
1016            help_data: use_kw.into(),
1017        }],
1018    ))
1019}
1020
1021fn use_exp(s: Span) -> IResult<Span, Vec<Lang>> {
1022    let res = (
1023        tag("use("),
1024        chars,
1025        tag(", "),
1026        alt((vector, chars)),
1027        terminated(tag(");"), multispace0),
1028    )
1029        .parse(s);
1030    match res {
1031        Ok((s, (us, lib, _, members, _))) => Ok((
1032            s,
1033            vec![Lang::Use {
1034                lang: Box::new(lib),
1035                members: Box::new(members),
1036                help_data: us.into(),
1037            }],
1038        )),
1039        Err(r) => Err(r),
1040    }
1041}
1042
1043fn custom_operators(s: Span) -> IResult<Span, (String, HelpData)> {
1044    let res = custom_op.parse(s);
1045    match res {
1046        Ok((s, co)) => Ok((s, (co.clone().to_string(), co.into()))),
1047        Err(r) => Err(r),
1048    }
1049}
1050
1051fn return_stmt(s: Span) -> IResult<Span, Vec<Lang>> {
1052    let (s, e) = return_exp(s)?;
1053    Ok((s, vec![e]))
1054}
1055
1056fn stmt_exp(s: Span) -> IResult<Span, Vec<Lang>> {
1057    let res = (parse_elements, terminated(tag(";"), multispace0)).parse(s);
1058    match res {
1059        Ok((s, (lang, _))) => Ok((s, vec![lang])),
1060        Err(r) => Err(r),
1061    }
1062}
1063
1064fn head_lang(lang: &Lang) -> Option<Lang> {
1065    match lang {
1066        Lang::Variable { .. } => Some(lang.clone()),
1067        Lang::Operator {
1068            operator: Op::Pipe(_) | Op::Dot(_),
1069            rhs,
1070            ..
1071        } => head_lang(rhs),
1072        _ => None,
1073    }
1074}
1075
1076fn implicit_mutate(s: Span) -> IResult<Span, Vec<Lang>> {
1077    let res = (parse_elements, terminated(tag("!;"), multispace0)).parse(s);
1078    match res {
1079        Ok((s, (expr, excl))) => match head_lang(&expr) {
1080            Some(lhs) => Ok((
1081                s,
1082                vec![Lang::Assign {
1083                    identifier: Box::new(lhs),
1084                    expression: Box::new(expr),
1085                    help_data: excl.into(),
1086                }],
1087            )),
1088            None => {
1089                push_parse_error(SyntaxError::MutationTargetNotAssignable(
1090                    expr.clone().into(),
1091                ));
1092                Err(nom::Err::Error(nom::error::Error::new(
1093                    s,
1094                    nom::error::ErrorKind::Tag,
1095                )))
1096            }
1097        },
1098        Err(r) => Err(r),
1099    }
1100}
1101
1102fn signature_variable(s: Span) -> IResult<Span, Vec<Lang>> {
1103    let res = (
1104        tag("@"),
1105        alt((variable_recognizer, custom_operators)),
1106        terminated(tag(":"), multispace0),
1107        ltype,
1108        terminated(tag(";"), multispace0),
1109    )
1110        .parse(s);
1111    match res {
1112        Ok((s, (at, (name, h), _col, typ, _))) => {
1113            let var2 = Var::from_name(&name).set_help_data(h).set_type(typ.clone());
1114            Ok((
1115                s,
1116                vec![Lang::Signature {
1117                    identifier: var2,
1118                    target_type: typ,
1119                    help_data: at.into(),
1120                }],
1121            ))
1122        }
1123        Err(r) => Err(r),
1124    }
1125}
1126
1127fn signature_opaque(s: Span) -> IResult<Span, Vec<Lang>> {
1128    let res = (
1129        tag("@"),
1130        type_alias,
1131        terminated(tag(":"), multispace0),
1132        ltype,
1133        terminated(tag(";"), multispace0),
1134    )
1135        .parse(s);
1136    match res {
1137        Ok((s, (at, Type::Alias(name, _params, _, h), _, typ, _))) => {
1138            let var2 = Var::from_name(&name)
1139                .set_help_data(h.clone())
1140                .set_type(typ.clone());
1141            Ok((
1142                s,
1143                vec![Lang::Signature {
1144                    identifier: var2,
1145                    target_type: typ,
1146                    help_data: at.into(),
1147                }],
1148            ))
1149        }
1150        Ok((_s, (_, _, _, _, _))) => todo!(),
1151        Err(r) => Err(r),
1152    }
1153}
1154
1155pub fn signature(s: Span) -> IResult<Span, Vec<Lang>> {
1156    alt((signature_opaque, signature_variable)).parse(s)
1157}
1158
1159fn for_loop(s: Span) -> IResult<Span, Vec<Lang>> {
1160    let res = (
1161        terminated(tag("for"), multispace0),
1162        terminated(tag("("), multispace0),
1163        terminated(variable_exp, multispace0),
1164        terminated(tag("in"), multispace0),
1165        terminated(single_element, multispace0),
1166        terminated(tag(")"), multispace0),
1167        scope,
1168        terminated(tag(";"), multispace0),
1169    )
1170        .parse(s);
1171    match res {
1172        Ok((s, (_for, _op, (var_str, _h), _in, iterator, _cl, scop, _semi))) => Ok((
1173            s,
1174            vec![Lang::ForLoop {
1175                identifier: Var::from_name(&var_str),
1176                expression: Box::new(iterator),
1177                body: Box::new(scop),
1178                help_data: _for.into(),
1179            }],
1180        )),
1181        Err(r) => Err(r),
1182    }
1183}
1184
1185fn while_loop(s: Span) -> IResult<Span, Vec<Lang>> {
1186    let res = (
1187        terminated(tag("while"), multispace0),
1188        terminated(tag("("), multispace0),
1189        terminated(single_element, multispace0),
1190        terminated(tag(")"), multispace0),
1191        scope,
1192        terminated(tag(";"), multispace0),
1193    )
1194        .parse(s);
1195    match res {
1196        Ok((s, (_while, _op, condition, _cl, scop, _semi))) => Ok((
1197            s,
1198            vec![Lang::WhileLoop {
1199                condition: Box::new(condition),
1200                body: Box::new(scop),
1201                help_data: _while.into(),
1202            }],
1203        )),
1204        Err(r) => Err(r),
1205    }
1206}
1207
1208fn loop_loop(s: Span) -> IResult<Span, Vec<Lang>> {
1209    let res = (
1210        terminated(tag("loop"), multispace0),
1211        scope,
1212        terminated(tag(";"), multispace0),
1213    )
1214        .parse(s);
1215    match res {
1216        Ok((s, (_loop, scop, _semi))) => Ok((
1217            s,
1218            vec![Lang::Loop {
1219                body: Box::new(scop),
1220                help_data: _loop.into(),
1221            }],
1222        )),
1223        Err(r) => Err(r),
1224    }
1225}
1226
1227fn test_block(s: Span) -> IResult<Span, Vec<Lang>> {
1228    let res = (terminated(tag("Test"), multispace0), scope).parse(s);
1229    //parse_block).parse(s);
1230
1231    match res {
1232        Ok((s, (tst, body))) => Ok((
1233            s,
1234            vec![Lang::TestBlock {
1235                value: Box::new(body),
1236                help_data: tst.into(),
1237            }],
1238        )),
1239        Err(r) => Err(r),
1240    }
1241}
1242
1243// main
1244pub fn base_parse(s: Span) -> IResult<Span, Vec<Lang>> {
1245    let res = (
1246        opt(multispace0),
1247        many0(alt((
1248            alt((
1249                library,
1250                break_exp,
1251                next_exp,
1252                use_exp,
1253                test_block,
1254                while_loop,
1255                loop_loop,
1256                for_loop,
1257                signature,
1258                tests,
1259                import_module,
1260                use_module_directive,
1261                import_type,
1262            )),
1263            alt((
1264                import_var,
1265                mod_imp,
1266                comment,
1267                typeconstructor_exp,
1268                type_exp,
1269                type_instead_of_let_exp,
1270                opaque_exp,
1271                let_tuple_exp,
1272                let_exp,
1273                module,
1274                assign,
1275                return_stmt,
1276                implicit_mutate,
1277                stmt_exp,
1278            )),
1279        ))),
1280        opt(parse_elements),
1281    )
1282        .parse(s);
1283    match res {
1284        // Case 1: nothing → empty vec (truly empty, distinct from `...`)
1285        Ok((s, (_, v, None))) if v.is_empty() => Ok((s, vec![])),
1286        // Case 2: no statements, one trailing expression (no ";") → return it directly
1287        Ok((s, (_, v, Some(expr)))) if v.is_empty() => Ok((s, vec![expr])),
1288        // Case 3: one or more statements + optional trailing expression
1289        Ok((s, (_, v, trailing))) => {
1290            let mut result: Vec<Lang> = v.into_iter().flatten().collect();
1291            if let Some(expr) = trailing {
1292                result.push(expr);
1293            }
1294            Ok((s, result))
1295        }
1296        Err(r) => Err(r),
1297    }
1298}
1299
1300/// Parse source code and return a ParseResult containing the AST and any syntax errors
1301///
1302/// This function collects syntax errors instead of panicking, allowing the caller
1303/// to handle errors appropriately (e.g., display all errors, continue with partial AST)
1304pub fn parse(s: Span) -> ParseResult {
1305    let res = base_parse(s.clone());
1306    match res {
1307        Ok((remaining, v)) => {
1308            if !remaining.fragment().is_empty() {
1309                let element = remaining
1310                    .fragment()
1311                    .lines()
1312                    .next()
1313                    .unwrap_or("")
1314                    .trim()
1315                    .to_string();
1316                let line = remaining.location_line();
1317                let help_data = HelpData::from(remaining);
1318                push_parse_error(SyntaxError::UnknownElement {
1319                    element,
1320                    line,
1321                    help_data,
1322                });
1323            }
1324            ParseResult::new(Lang::Lines {
1325                value: v.clone(),
1326                help_data: v.into(),
1327            })
1328        }
1329        Err(_) => panic!("Can't parse string {}", s),
1330    }
1331}
1332
1333/// Parse source code and return just the Lang AST (legacy behavior)
1334///
1335/// This function is kept for backwards compatibility. It returns the AST directly
1336/// and will panic if parsing fails completely.
1337pub fn parse_legacy(s: Span) -> Lang {
1338    parse(s).ast
1339}
1340
1341pub fn parse2(s: Span) -> Result<Lang, String> {
1342    let res = base_parse(s.clone());
1343    // Drain any parse errors collected during parsing (e.g. ForgottenSemicolon, FunctionTypeSyntax)
1344    let _ = take_parse_errors();
1345    match res {
1346        Ok((_, v)) => Ok(v[0].clone()),
1347        Err(_) => Err(format!("Can't parse string {}", s)),
1348    }
1349}
1350
1351/// Parse source code from a string with a filename for error reporting
1352///
1353/// This is the main entry point for parsing source code in the public API.
1354/// It registers the source for error display and returns the AST.
1355pub fn parse_from_string(source: &str, filename: &str) -> Lang {
1356    use crate::components::error_message::help_data::register_source;
1357
1358    // Register source for error display
1359    register_source(filename, source);
1360
1361    // Create a span with the filename as extra data
1362    let span: Span = LocatedSpan::new_extra(source, filename.to_string());
1363
1364    // Parse and return the AST
1365    parse(span).ast
1366}
1367
1368/// Parse source code from a string with a filename, returning full ParseResult
1369pub fn parse_from_string_with_errors(source: &str, filename: &str) -> ParseResult {
1370    use crate::components::error_message::help_data::register_source;
1371
1372    // Register source for error display
1373    register_source(filename, source);
1374
1375    // Create a span with the filename as extra data
1376    let span: Span = LocatedSpan::new_extra(source, filename.to_string());
1377
1378    // Parse and return full result
1379    parse(span)
1380}
1381
1382// main test
1383#[cfg(test)]
1384mod tesus {
1385    use super::*;
1386
1387    #[test]
1388    fn test_semicolon1() {
1389        let res = parse("let a <- 5".into());
1390        // This should now collect a ForgottenSemicolon error
1391        assert!(
1392            res.has_errors(),
1393            "Missing semicolon should produce a syntax error"
1394        );
1395        assert_eq!(res.errors.len(), 1, "Should have exactly one error");
1396        match &res.errors[0] {
1397            SyntaxError::ForgottenSemicolon(_) => (),
1398            _ => panic!("Expected ForgottenSemicolon error"),
1399        }
1400    }
1401
1402    #[test]
1403    fn test_semicolon_standalone_exp() {
1404        let res = parse("f(x)".into());
1405        // Case 2: a single expression without ";" is valid — no error
1406        assert!(
1407            !res.has_errors(),
1408            "A standalone expression without semicolon is valid (case 2)"
1409        );
1410    }
1411
1412    #[test]
1413    fn test_semicolon_assign() {
1414        let res = parse("a <- 12".into());
1415        assert!(
1416            res.has_errors(),
1417            "An assign expression without semicolon should produce a syntax error"
1418        );
1419        match &res.errors[0] {
1420            SyntaxError::ForgottenSemicolon(_) => (),
1421            _ => panic!("Expected ForgottenSemicolon error"),
1422        }
1423    }
1424
1425    #[test]
1426    fn test_assign1() {
1427        let res = assign("a <- 12;".into()).unwrap().1;
1428        assert_eq!(
1429            "Assign",
1430            res[0].simple_print(),
1431            "The expression 'a <- 12;' should be identified as an assignation"
1432        );
1433    }
1434
1435    // ==================== Let vs Type Alias Tests ====================
1436
1437    #[test]
1438    fn test_let_instead_of_type() {
1439        let res = parse("let MyType <- int;".into());
1440        assert!(
1441            res.has_errors(),
1442            "let with PascalCase should produce a syntax error"
1443        );
1444        assert_eq!(res.errors.len(), 1, "Should have exactly one error");
1445        match &res.errors[0] {
1446            SyntaxError::LetInsteadOfType { name, .. } => {
1447                assert_eq!(name, "MyType", "Error should reference the type name");
1448            }
1449            _ => panic!("Expected LetInsteadOfType error"),
1450        }
1451    }
1452
1453    #[test]
1454    fn test_let_instead_of_type_with_pub() {
1455        let res = parse("@pub let MyAlias <- num;".into());
1456        assert!(
1457            res.has_errors(),
1458            "@pub let with PascalCase should produce a syntax error"
1459        );
1460        assert!(res
1461            .errors
1462            .iter()
1463            .any(|e| matches!(e, SyntaxError::LetInsteadOfType { .. })));
1464    }
1465
1466    #[test]
1467    fn test_let_with_lowercase_is_fine() {
1468        let res = parse("let my_var <- 42;".into());
1469        assert!(
1470            !res.has_errors(),
1471            "let with snake_case should not produce a syntax error"
1472        );
1473    }
1474
1475    #[test]
1476    fn test_type_instead_of_let() {
1477        let res = parse("type my_var <- 42;".into());
1478        assert!(
1479            res.has_errors(),
1480            "type with snake_case should produce a syntax error"
1481        );
1482        assert_eq!(res.errors.len(), 1, "Should have exactly one error");
1483        match &res.errors[0] {
1484            SyntaxError::TypeInsteadOfLet { name, .. } => {
1485                assert_eq!(name, "my_var", "Error should reference the variable name");
1486            }
1487            _ => panic!("Expected TypeInsteadOfLet error"),
1488        }
1489    }
1490
1491    #[test]
1492    fn test_type_instead_of_let_with_pub() {
1493        let res = parse("@pub type my_binding <- num;".into());
1494        assert!(
1495            res.has_errors(),
1496            "@pub type with snake_case should produce a syntax error"
1497        );
1498        assert!(res
1499            .errors
1500            .iter()
1501            .any(|e| matches!(e, SyntaxError::TypeInsteadOfLet { .. })));
1502    }
1503
1504    #[test]
1505    fn test_type_with_pascalcase_is_fine() {
1506        let res = parse("type MyAlias <- int;".into());
1507        assert!(
1508            !res.has_errors(),
1509            "type with PascalCase should not produce a syntax error"
1510        );
1511    }
1512
1513    // ==================== Let Tuple Destructuring Tests ====================
1514
1515    #[test]
1516    fn test_let_tuple_basic() {
1517        let res = let_tuple_exp("let :{a, b, c} <- :{1, 2, 3};".into())
1518            .unwrap()
1519            .1;
1520        // Should produce 4 Let statements: 1 tmp + 3 bindings
1521        assert_eq!(
1522            res.len(),
1523            4,
1524            "Should produce 4 Let statements (1 tmp + 3 bindings)"
1525        );
1526        for item in &res {
1527            assert!(
1528                item.simple_print().starts_with("let"),
1529                "Each item should be a Let, got: {}",
1530                item.simple_print()
1531            );
1532        }
1533    }
1534
1535    #[test]
1536    fn test_let_tuple_tmp_variable() {
1537        let res = let_tuple_exp("let :{a, b} <- :{1, 2};".into()).unwrap().1;
1538        // First Let should bind __tuple_tmp__
1539        if let Lang::Let { variable: var, .. } = &res[0] {
1540            if let Lang::Variable { name, .. } = var.as_ref() {
1541                assert_eq!(name, "__tuple_tmp__");
1542            } else {
1543                panic!("Expected Variable in first Let");
1544            }
1545        } else {
1546            panic!("Expected Let");
1547        }
1548    }
1549
1550    #[test]
1551    fn test_let_tuple_bindings() {
1552        let res = let_tuple_exp("let :{x, y} <- :{10, 20};".into()).unwrap().1;
1553        // Second Let should bind 'x' using Dot access
1554        if let Lang::Let {
1555            variable: var,
1556            expression: body,
1557            ..
1558        } = &res[1]
1559        {
1560            if let Lang::Variable { name, .. } = var.as_ref() {
1561                assert_eq!(name, "x");
1562            } else {
1563                panic!("Expected Variable 'x'");
1564            }
1565            assert_eq!(
1566                body.simple_print(),
1567                "Operator",
1568                "Body should be a Dot operator"
1569            );
1570        } else {
1571            panic!("Expected Let");
1572        }
1573        // Third Let should bind 'y'
1574        if let Lang::Let { variable: var, .. } = &res[2] {
1575            if let Lang::Variable { name, .. } = var.as_ref() {
1576                assert_eq!(name, "y");
1577            } else {
1578                panic!("Expected Variable 'y'");
1579            }
1580        } else {
1581            panic!("Expected Let");
1582        }
1583    }
1584
1585    #[test]
1586    fn test_let_tuple_wildcard() {
1587        let res = let_tuple_exp("let :{a, _, c} <- :{1, 2, 3};".into())
1588            .unwrap()
1589            .1;
1590        // Should produce 3 Let statements: 1 tmp + 2 bindings (wildcard skipped)
1591        assert_eq!(
1592            res.len(),
1593            3,
1594            "Should produce 3 Let statements (wildcard skipped)"
1595        );
1596        // Second Let should bind 'a'
1597        if let Lang::Let { variable: var, .. } = &res[1] {
1598            if let Lang::Variable { name, .. } = var.as_ref() {
1599                assert_eq!(name, "a");
1600            } else {
1601                panic!("Expected Variable 'a'");
1602            }
1603        } else {
1604            panic!("Expected Let");
1605        }
1606        // Third Let should bind 'c'
1607        if let Lang::Let { variable: var, .. } = &res[2] {
1608            if let Lang::Variable { name, .. } = var.as_ref() {
1609                assert_eq!(name, "c");
1610            } else {
1611                panic!("Expected Variable 'c'");
1612            }
1613        } else {
1614            panic!("Expected Let");
1615        }
1616    }
1617
1618    #[test]
1619    fn test_let_tuple_in_full_parse() {
1620        let res = parse("let :{a, b, c} <- :{1, 2, 3};".into());
1621        assert!(
1622            !res.has_errors(),
1623            "Let tuple destructuring should parse without errors"
1624        );
1625    }
1626
1627    #[test]
1628    fn test_let_tuple_with_equals() {
1629        let res = let_tuple_exp("let :{a, b} = :{1, 2};".into()).unwrap().1;
1630        assert_eq!(res.len(), 3, "Should work with '=' operator too");
1631    }
1632
1633    #[test]
1634    fn test_let_tuple_type_check() {
1635        use crate::components::context::Context;
1636        use crate::processes::type_checking::typing;
1637        use crate::utils::builder;
1638
1639        let ast = parse("let :{a, b, c} <- :{1, 2, 3};".into()).ast;
1640        let context = Context::empty();
1641        let tc = typing(&context, &ast);
1642
1643        // After type-checking, 'a', 'b', 'c' should be in the context as integers
1644        let ty_a = tc
1645            .context
1646            .get_type_from_existing_variable(crate::components::language::var::Var::from_name("a"));
1647        let ty_b = tc
1648            .context
1649            .get_type_from_existing_variable(crate::components::language::var::Var::from_name("b"));
1650        let ty_c = tc
1651            .context
1652            .get_type_from_existing_variable(crate::components::language::var::Var::from_name("c"));
1653
1654        assert_eq!(
1655            ty_a,
1656            builder::integer_type(1),
1657            "Variable 'a' should be Integer(1)"
1658        );
1659        assert_eq!(
1660            ty_b,
1661            builder::integer_type(2),
1662            "Variable 'b' should be Integer(2)"
1663        );
1664        assert_eq!(
1665            ty_c,
1666            builder::integer_type(3),
1667            "Variable 'c' should be Integer(3)"
1668        );
1669    }
1670
1671    #[test]
1672    fn test_let_tuple_type_check_mixed_types() {
1673        use crate::components::context::Context;
1674        use crate::processes::type_checking::typing;
1675        use crate::utils::builder;
1676
1677        let ast = parse("let :{x, y} <- :{1, 'hello'};".into()).ast;
1678        let context = Context::empty();
1679        let tc = typing(&context, &ast);
1680
1681        let ty_x = tc
1682            .context
1683            .get_type_from_existing_variable(crate::components::language::var::Var::from_name("x"));
1684        let ty_y = tc
1685            .context
1686            .get_type_from_existing_variable(crate::components::language::var::Var::from_name("y"));
1687
1688        assert_eq!(
1689            ty_x,
1690            builder::integer_type(1),
1691            "Variable 'x' should be Integer(1)"
1692        );
1693        assert_eq!(
1694            ty_y,
1695            builder::character_type("hello"),
1696            "Variable 'y' should be Character('hello')"
1697        );
1698    }
1699
1700    #[test]
1701    fn test_fn_function_type_syntax_error() {
1702        let res = parse("let f: fn(a: int) -> int <- fn(x: int): int { x };".into());
1703        assert!(
1704            res.has_errors(),
1705            "Using 'fn(...)' in type position should produce a syntax error"
1706        );
1707        let fn_type_error = res
1708            .errors
1709            .iter()
1710            .any(|e| matches!(e, SyntaxError::FunctionTypeSyntax(_)));
1711        assert!(
1712            fn_type_error,
1713            "Expected FunctionTypeSyntax error, got: {:?}",
1714            res.errors
1715        );
1716    }
1717
1718    #[test]
1719    fn test_use_wildcard_parses() {
1720        use crate::components::language::use_lang::UseSelector;
1721        let lang = parse2("use Math::*;".into()).expect("parse failed");
1722        match lang {
1723            Lang::UseModule {
1724                module_path,
1725                selector,
1726                ..
1727            } => {
1728                assert_eq!(module_path, vec!["Math".to_string()]);
1729                assert_eq!(selector, UseSelector::Wildcard);
1730            }
1731            other => panic!("Expected UseModule, got {:?}", other),
1732        }
1733    }
1734
1735    #[test]
1736    fn test_use_items_parses() {
1737        use crate::components::language::use_lang::{UseItem, UseSelector};
1738        let lang = parse2("use Math::{pi, sin as s};".into()).expect("parse failed");
1739        match lang {
1740            Lang::UseModule {
1741                module_path,
1742                selector,
1743                ..
1744            } => {
1745                assert_eq!(module_path, vec!["Math".to_string()]);
1746                assert_eq!(
1747                    selector,
1748                    UseSelector::Items(vec![
1749                        UseItem {
1750                            name: "pi".to_string(),
1751                            alias: None
1752                        },
1753                        UseItem {
1754                            name: "sin".to_string(),
1755                            alias: Some("s".to_string())
1756                        },
1757                    ])
1758                );
1759            }
1760            other => panic!("Expected UseModule, got {:?}", other),
1761        }
1762    }
1763
1764    #[test]
1765    fn test_use_nested_path_parses() {
1766        use crate::components::language::use_lang::UseSelector;
1767        let lang = parse2("use Aa::Bb::Cc::*;".into()).expect("parse failed");
1768        match lang {
1769            Lang::UseModule {
1770                module_path,
1771                selector,
1772                ..
1773            } => {
1774                assert_eq!(
1775                    module_path,
1776                    vec!["Aa".to_string(), "Bb".to_string(), "Cc".to_string()]
1777                );
1778                assert_eq!(selector, UseSelector::Wildcard);
1779            }
1780            other => panic!("Expected UseModule, got {:?}", other),
1781        }
1782    }
1783
1784    #[test]
1785    fn test_implicit_mutate_simple_variable() {
1786        let res = implicit_mutate("x!;".into()).unwrap().1;
1787        assert_eq!(res.len(), 1);
1788        match &res[0] {
1789            Lang::Assign {
1790                identifier,
1791                expression,
1792                ..
1793            } => {
1794                assert!(matches!(identifier.as_ref(), Lang::Variable { .. }));
1795                assert!(matches!(expression.as_ref(), Lang::Variable { .. }));
1796            }
1797            other => panic!("Expected Assign, got {:?}", other),
1798        }
1799    }
1800
1801    #[test]
1802    fn test_implicit_mutate_pipeline() {
1803        let res = implicit_mutate("x |> f()!;".into()).unwrap().1;
1804        assert_eq!(res.len(), 1);
1805        match &res[0] {
1806            Lang::Assign {
1807                identifier,
1808                expression,
1809                ..
1810            } => {
1811                assert!(matches!(identifier.as_ref(), Lang::Variable { .. }));
1812                assert!(matches!(expression.as_ref(), Lang::Operator { .. }));
1813            }
1814            other => panic!("Expected Assign, got {:?}", other),
1815        }
1816    }
1817
1818    #[test]
1819    fn test_implicit_mutate_ufc() {
1820        let res = implicit_mutate("obj.method()!;".into()).unwrap().1;
1821        assert_eq!(res.len(), 1);
1822        match &res[0] {
1823            Lang::Assign { identifier, .. } => match identifier.as_ref() {
1824                Lang::Variable { name, .. } => assert_eq!(name, "obj"),
1825                other => panic!("Expected Variable identifier, got {:?}", other),
1826            },
1827            other => panic!("Expected Assign, got {:?}", other),
1828        }
1829    }
1830
1831    #[test]
1832    fn test_implicit_mutate_pipeline_chained() {
1833        let res = implicit_mutate("x |> f() |> g()!;".into()).unwrap().1;
1834        assert_eq!(res.len(), 1);
1835        match &res[0] {
1836            Lang::Assign { identifier, .. } => match identifier.as_ref() {
1837                Lang::Variable { name, .. } => assert_eq!(name, "x"),
1838                other => panic!("Expected Variable identifier, got {:?}", other),
1839            },
1840            other => panic!("Expected Assign, got {:?}", other),
1841        }
1842    }
1843
1844    #[test]
1845    fn test_implicit_mutate_ufc_pipeline() {
1846        let res = implicit_mutate("shape.scale(2) |> rotate(90)!;".into())
1847            .unwrap()
1848            .1;
1849        assert_eq!(res.len(), 1);
1850        match &res[0] {
1851            Lang::Assign { identifier, .. } => match identifier.as_ref() {
1852                Lang::Variable { name, .. } => assert_eq!(name, "shape"),
1853                other => panic!("Expected Variable identifier, got {:?}", other),
1854            },
1855            other => panic!("Expected Assign, got {:?}", other),
1856        }
1857    }
1858
1859    #[test]
1860    fn test_implicit_mutate_invalid_literal_fails() {
1861        // 3!; — literal, not assignable: parser should fail (return Err)
1862        let res = implicit_mutate("3!;".into());
1863        assert!(res.is_err(), "Literal mutation should fail to parse");
1864    }
1865}