Skip to main content

typr_core/processes/parsing/
elements.rs

1use crate::components::error_message::help_data::HelpData;
2use crate::components::error_message::help_message::ErrorMsg;
3use crate::components::error_message::syntax_error::SyntaxError;
4use crate::components::language::argument_value::ArgumentValue;
5use crate::components::language::operators::op;
6use crate::components::language::operators::Op;
7use crate::components::language::var::Var;
8use crate::components::language::Lang;
9use crate::components::r#type::argument_type::ArgumentType;
10use crate::components::r#type::Type;
11use crate::processes::parsing::base_parse;
12use crate::processes::parsing::lang_token::LangToken;
13use crate::processes::parsing::operation_priority::PriorityTokens;
14use crate::processes::parsing::types::if_type;
15use crate::processes::parsing::types::label;
16use crate::processes::parsing::types::ltype;
17use crate::processes::parsing::types::pascal_case_no_space;
18use crate::processes::parsing::types::primitive_types;
19
20use crate::processes::parsing::vector_priority::VectorPriority;
21use crate::utils::builder;
22use nom::branch::alt;
23use nom::bytes::complete::escaped;
24use nom::bytes::complete::is_not;
25use nom::bytes::complete::tag;
26use nom::bytes::complete::take_while1;
27use nom::character::complete::alpha1;
28use nom::character::complete::alphanumeric1;
29use nom::character::complete::char;
30use nom::character::complete::digit1;
31use nom::character::complete::multispace0;
32use nom::character::complete::multispace1;
33use nom::character::complete::one_of;
34use nom::combinator::not;
35use nom::combinator::opt;
36use nom::combinator::recognize;
37use nom::multi::many0;
38use nom::multi::many1;
39use nom::sequence::delimited;
40use nom::sequence::preceded;
41use nom::sequence::terminated;
42use nom::IResult;
43use nom::Parser;
44use nom_locate::LocatedSpan;
45use std::process::exit;
46
47type Span<'a> = LocatedSpan<&'a str, String>;
48
49pub fn is_pascal_case(name: &str) -> bool {
50    let res = recognize(pascal_case_no_space).parse(name.into());
51    match res {
52        Ok((_, _)) => true,
53        Err(_) => false,
54    }
55}
56
57fn number_helper(s: Span) -> IResult<Span, Lang> {
58    let res = (opt(tag("-")), digit1, tag("."), digit1).parse(s);
59    match res {
60        Ok((s, (sign, d1, _dot, d2))) => {
61            let sign2 = sign.unwrap_or(LocatedSpan::new_extra("", d1.clone().extra));
62            let n = format!("{}{}.{}", sign2, d1, d2).parse::<f32>().unwrap();
63            Ok((
64                s,
65                Lang::Number {
66                    value: n,
67                    help_data: sign2.into(),
68                },
69            ))
70        }
71        Err(r) => Err(r),
72    }
73}
74
75pub fn number(s: Span) -> IResult<Span, Lang> {
76    terminated(number_helper, multispace0).parse(s)
77}
78
79fn integer(s: Span) -> IResult<Span, Lang> {
80    let res = terminated((opt(tag("-")), digit1), multispace0).parse(s);
81    match res {
82        Ok((s, (minus, d))) => {
83            let symbol = match minus {
84                Some(_) => "-",
85                None => "",
86            }
87            .to_string()
88                + d.as_ref();
89            Ok((
90                s,
91                Lang::Integer {
92                    value: symbol.parse::<i32>().unwrap(),
93                    help_data: d.into(),
94                },
95            ))
96        }
97        Err(r) => Err(r),
98    }
99}
100
101fn get_value(l: LocatedSpan<&str, String>) -> Lang {
102    match l.clone().into_fragment() {
103        "true" | "TRUE" => Lang::Bool {
104            value: true,
105            help_data: l.into(),
106        },
107        "false" | "FALSE" => Lang::Bool {
108            value: false,
109            help_data: l.into(),
110        },
111        _ => panic!("No other boolean notation alolwed"),
112    }
113}
114
115fn null_value(s: Span) -> IResult<Span, Lang> {
116    let res = alt((
117        terminated(terminated(tag("NULL"), not(body_char)), multispace0),
118        terminated(terminated(tag("null"), not(body_char)), multispace0),
119    ))
120    .parse(s);
121    match res {
122        Ok((s, n)) => Ok((s, Lang::Null(n.into()))),
123        Err(r) => Err(r),
124    }
125}
126
127fn na_value(s: Span) -> IResult<Span, Lang> {
128    let res = alt((
129        terminated(terminated(tag("NA"), not(body_char)), multispace0),
130        terminated(terminated(tag("na"), not(body_char)), multispace0),
131    ))
132    .parse(s);
133    match res {
134        Ok((s, n)) => Ok((s, Lang::NA(n.into()))),
135        Err(r) => Err(r),
136    }
137}
138
139fn boolean(s: Span) -> IResult<Span, Lang> {
140    let res = alt((
141        terminated(terminated(tag("true"), not(body_char)), multispace0),
142        terminated(terminated(tag("TRUE"), not(body_char)), multispace0),
143        terminated(terminated(tag("false"), not(body_char)), multispace0),
144        terminated(terminated(tag("FALSE"), not(body_char)), multispace0),
145    ))
146    .parse(s);
147    match res {
148        Ok((s, ls)) => Ok((s, get_value(ls))),
149        Err(r) => Err(r),
150    }
151}
152
153pub fn chars(s: Span) -> IResult<Span, Lang> {
154    terminated(alt((double_quotes, single_quotes)), multispace0).parse(s)
155}
156
157pub fn double_quotes(input: Span) -> IResult<Span, Lang> {
158    let res = delimited(
159        char('"'),
160        opt(escaped(is_not("\\\""), '\\', alt((char('"'), char('\''))))),
161        char('"'),
162    )
163    .parse(input);
164    match res {
165        Ok((s, st)) => {
166            let content = st.clone().map(|span| span.to_string()).unwrap_or_default();
167            let location = st
168                .map(|span| span.into())
169                .unwrap_or_else(|| s.clone().into());
170            Ok((
171                s,
172                Lang::Char {
173                    value: content,
174                    help_data: location,
175                },
176            ))
177        }
178        Err(r) => Err(r),
179    }
180}
181
182pub fn single_quotes(input: Span) -> IResult<Span, Lang> {
183    let res = delimited(
184        char('\''),
185        opt(escaped(is_not("\\'"), '\\', alt((char('"'), char('\''))))),
186        char('\''),
187    )
188    .parse(input);
189    match res {
190        Ok((s, st)) => {
191            let content = st.clone().map(|span| span.to_string()).unwrap_or_default();
192            let location = st
193                .map(|span| span.into())
194                .unwrap_or_else(|| s.clone().into());
195            Ok((
196                s,
197                Lang::Char {
198                    value: content,
199                    help_data: location,
200                },
201            ))
202        }
203        Err(r) => Err(r),
204    }
205}
206
207fn starting_char(s: Span) -> IResult<Span, (char, HelpData)> {
208    let res = one_of("abcdefghijklmnopqrstuvwxyz_")(s);
209    match res {
210        Ok((s, val)) => Ok((s.clone(), (val, s.into()))),
211        Err(r) => Err(r),
212    }
213}
214
215fn body_char(s: Span) -> IResult<Span, (char, HelpData)> {
216    let res = one_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")(s);
217    match res {
218        Ok((s, val)) => Ok((s.clone(), (val, s.into()))),
219        Err(r) => Err(r),
220    }
221}
222
223pub fn variable_exp(s: Span) -> IResult<Span, (String, HelpData)> {
224    let res = (starting_char, many0(body_char)).parse(s);
225    match res {
226        Ok((s, ((s1, h), v))) => {
227            let res2 = v.iter().map(|(val, _h)| *val).collect::<String>();
228            Ok((s, (format!("{}{}", s1, res2), h.clone())))
229        }
230        Err(r) => Err(r),
231    }
232}
233
234fn type_annotation(s: Span) -> IResult<Span, Type> {
235    delimited(tag("<"), ltype, tag(">")).parse(s)
236}
237
238pub enum Case {
239    Maj,
240    Min,
241}
242
243fn variable_exp_2(s: Span) -> IResult<Span, (String, Case, HelpData)> {
244    let res = variable_exp.parse(s);
245    match res {
246        Ok((s, (name, h))) => Ok((s, (name, Case::Min, h))),
247        Err(r) => Err(r),
248    }
249}
250
251fn pascal_case_2(s: Span) -> IResult<Span, (String, Case, HelpData)> {
252    let res = pascal_case.parse(s);
253    match res {
254        Ok((s, (name, h))) => Ok((s, (name, Case::Maj, h))),
255        Err(r) => Err(r),
256    }
257}
258
259fn quoted_variable(s: Span) -> IResult<Span, (String, Case, HelpData)> {
260    let res = delimited(char('`'), is_not("`"), char('`')).parse(s);
261
262    match res {
263        Ok((s, st)) => Ok((s, (format!("`{}`", st.clone()), Case::Min, st.into()))),
264        Err(r) => Err(r),
265    }
266}
267
268pub fn variable_recognizer(s: Span) -> IResult<Span, (String, HelpData)> {
269    let res = alt((quoted_variable, pascal_case_2, variable_exp_2)).parse(s);
270    match res {
271        Ok((s, (s1, _case, h))) => Ok((s, (s1, h))),
272        Err(r) => Err(r),
273    }
274}
275
276fn variable_helper(s: Span) -> IResult<Span, (Lang, Case)> {
277    let res = (
278        alt((quoted_variable, pascal_case_2, variable_exp_2)),
279        opt(type_annotation),
280    )
281        .parse(s);
282    match res {
283        Ok((s, ((v, case, h), typ))) => {
284            let res = Var::from_name(&v)
285                .set_type(typ.unwrap_or(builder::empty_type()))
286                .set_help_data(h);
287            Ok((s, (res.into(), case)))
288        }
289        Err(r) => Err(r),
290    }
291}
292
293pub fn variable(s: Span) -> IResult<Span, (Lang, Case)> {
294    terminated(variable_helper, multispace0).parse(s)
295}
296
297pub fn argument(s: Span) -> IResult<Span, ArgumentType> {
298    // Try variadic: `...name: T[,]`
299    let variadic = (
300        terminated(tag("..."), multispace0),
301        terminated(label, multispace0),
302        terminated(tag(":"), multispace0),
303        ltype,
304        opt(terminated(tag(","), multispace0)),
305    )
306        .parse(s.clone());
307    if let Ok((s2, (_, e1, _, e2, _))) = variadic {
308        return Ok((s2, ArgumentType(e1, e2, false, true)));
309    }
310
311    // Regular: `name: T[,]`
312    let res = (
313        terminated(label, multispace0),
314        terminated(tag(":"), multispace0),
315        ltype,
316        opt(terminated(tag(","), multispace0)),
317    )
318        .parse(s);
319    match res {
320        Ok((s, (e1, _, e2, _))) => Ok((s, ArgumentType(e1, e2, false, false))),
321        Err(r) => Err(r),
322    }
323}
324
325fn equality_params(s: Span) -> IResult<Span, Span> {
326    terminated(alt((tag("="), tag(":"))), multispace0).parse(s)
327}
328
329fn argument_val(s: Span) -> IResult<Span, ArgumentValue> {
330    let res = (
331        terminated(alphanumeric1, multispace0),
332        equality_params,
333        single_element,
334        opt(terminated(tag(","), multispace0)),
335    )
336        .parse(s);
337    match res {
338        Ok((s, (e1, _, e2, _))) => Ok((s, ArgumentValue(e1.to_string(), e2))),
339        Err(r) => Err(r),
340    }
341}
342
343pub fn parse_block(input: Span) -> IResult<Span, Span> {
344    recognize(parse_nested_braces).parse(input)
345}
346
347fn parse_nested_braces(input: Span) -> IResult<Span, Span> {
348    recognize(delimited(
349        tag("{"),
350        many0(alt((
351            parse_nested_braces,
352            recognize(take_while1(|c| c != '{' && c != '}')),
353        ))),
354        tag("}"),
355    ))
356    .parse(input)
357}
358
359pub fn r_function(s: Span) -> IResult<Span, Lang> {
360    let res = (
361        terminated(alt((tag("function"), tag("\\"))), multispace0),
362        terminated(tag("("), multispace0),
363        many0(terminated(terminated(variable, opt(tag(","))), multispace0)),
364        terminated(tag(")"), multispace0),
365        terminated(parse_block, multispace0),
366    )
367        .parse(s);
368    match res {
369        Ok((_s, (id, _op, _args, _cl, _exp))) if *id.fragment() == "fn" => {
370            panic!("{}", SyntaxError::FunctionWithoutType(id.into()).display())
371        }
372        Ok((s, (id, _op, args, _cl, exp))) => {
373            let args = args.iter().map(|(arg, _)| arg).cloned().collect::<Vec<_>>();
374            Ok((
375                s,
376                Lang::RFunction {
377                    parameters: args,
378                    body: exp.to_string(),
379                    help_data: id.into(),
380                },
381            ))
382        }
383        Err(r) => Err(r),
384    }
385}
386
387pub fn simple_function(s: Span) -> IResult<Span, Lang> {
388    let res = (
389        terminated(tag("fn"), multispace0),
390        terminated(tag("("), multispace0),
391        many0(argument),
392        terminated(tag(")"), multispace0),
393        opt(terminated(tag(":"), multispace0)),
394        opt(terminated(alt((if_type, ltype)), multispace0)),
395        //alt((scope, parse_elements))
396        scope,
397    )
398        .parse(s);
399    match res {
400        Ok((s, (_, _, args, _, Some(_), Some(typ), exp))) => Ok((
401            s,
402            Lang::Function {
403                parameters: args,
404                return_type: typ,
405                body: Box::new(exp),
406                help_data: HelpData::default(),
407            },
408        )),
409        Ok((_s, (_, _, _args, _cp, None, None, _exp))) => {
410            panic!("You forgot to specify the function return type: 'fn(...): Type'");
411        }
412        Ok((_s, (_, _, _args, _, Some(tag), None, _exp))) => {
413            panic!(
414                "{}",
415                SyntaxError::FunctionWithoutReturnType(tag.into()).display()
416            );
417        }
418        Ok((_s, (_, _, _args, _, None, Some(typ), _exp))) => {
419            eprintln!(
420                "The type '{}' should be preceded by a ':' :\n 'fn(...): {}'",
421                typ.clone(),
422                typ.clone()
423            );
424            exit(1)
425        }
426        Err(r) => Err(r),
427    }
428}
429
430fn function(s: Span) -> IResult<Span, Lang> {
431    simple_function.parse(s)
432}
433
434fn key_value(s: Span) -> IResult<Span, Lang> {
435    let res = (
436        recognize(variable),
437        terminated(tag("="), multispace0),
438        single_element,
439    )
440        .parse(s);
441    match res {
442        Ok((s, (v, _eq, el))) => Ok((
443            s,
444            Lang::KeyValue {
445                key: (*v).into(),
446                value: Box::new(el),
447                help_data: v.into(),
448            },
449        )),
450        Err(r) => Err(r),
451    }
452}
453
454fn values(s: Span) -> IResult<Span, Vec<Lang>> {
455    many0(terminated(
456        alt((key_value, parse_elements)),
457        terminated(opt(tag(",")), multispace0),
458    ))
459    .parse(s)
460}
461
462pub fn variable2(s: Span) -> IResult<Span, Lang> {
463    let res = variable.parse(s);
464    match res {
465        Ok((s, (lang, _))) => Ok((s, lang)),
466        Err(r) => Err(r),
467    }
468}
469
470fn array_indexing(s: Span) -> IResult<Span, Lang> {
471    let res = (alt((scope, variable2)), array).parse(s);
472
473    match res {
474        Ok((s, (lang1, lang2))) => Ok((
475            s,
476            Lang::ArrayIndexing {
477                identifier: Box::new(lang1.clone()),
478                indexing: Box::new(lang2),
479                help_data: lang1.into(),
480            },
481        )),
482        Err(r) => Err(r),
483    }
484}
485
486fn dataframe_exp(s: Span) -> IResult<Span, Lang> {
487    let res = (
488        alt((tag("data__frame"), tag("data.frame"))),
489        terminated(tag("("), multispace0),
490        many0(argument_val),
491        terminated(tag(")"), multispace0),
492    )
493        .parse(s);
494    match res {
495        Ok((s, (start, _, args, _))) => Ok((
496            s,
497            Lang::DataFrame {
498                value: args.clone(),
499                help_data: start.into(),
500            },
501        )),
502        Err(r) => Err(r),
503    }
504}
505
506fn function_application(s: Span) -> IResult<Span, Lang> {
507    let res = (
508        alt((scope, variable2)),
509        terminated(tag("("), multispace0),
510        values,
511        terminated(tag(")"), multispace0),
512    )
513        .parse(s);
514    match res {
515        Ok((s, (exp, _, v, _))) => Ok((
516            s,
517            Lang::FunctionApp {
518                identifier: Box::new(exp.clone()),
519                arguments: v.clone(),
520                help_data: exp.into(),
521            },
522        )),
523        Err(r) => Err(r),
524    }
525}
526
527fn array(s: Span) -> IResult<Span, Lang> {
528    let res = (
529        terminated(tag("["), multispace0),
530        values,
531        terminated(tag("]"), multispace0),
532    )
533        .parse(s);
534    match res {
535        Ok((s, (_, v, _))) => Ok((
536            s,
537            Lang::Array {
538                value: v.clone(),
539                help_data: v.into(),
540            },
541        )),
542        Err(r) => Err(r),
543    }
544}
545
546pub fn vector(s: Span) -> IResult<Span, Lang> {
547    let res = (
548        terminated(tag("c("), multispace0),
549        values,
550        terminated(tag(")"), multispace0),
551    )
552        .parse(s);
553    match res {
554        Ok((s, (_, v, _))) => Ok((
555            s,
556            Lang::Vector {
557                value: v.clone(),
558                help_data: v.into(),
559            },
560        )),
561        Err(r) => Err(r),
562    }
563}
564
565fn sequence(s: Span) -> IResult<Span, Lang> {
566    let res = (
567        terminated(tag("seq["), multispace0),
568        values,
569        terminated(tag("]"), multispace0),
570    )
571        .parse(s);
572    match res {
573        Ok((s, (_, v, _))) => Ok((
574            s,
575            Lang::Sequence {
576                body: v.clone(),
577                help_data: v.into(),
578            },
579        )),
580        Err(r) => Err(r),
581    }
582}
583
584fn constructor_call(s: Span) -> IResult<Span, Lang> {
585    let res = (
586        pascal_case,
587        terminated(tag(":"), multispace0),
588        terminated(tag("{"), multispace0),
589        many0(argument_val),
590        terminated(tag("}"), multispace0),
591    )
592        .parse(s);
593    match res {
594        Ok((s, ((name, h), _, _, args, _))) => Ok((
595            s,
596            Lang::ConstructorCall {
597                type_name: name,
598                fields: args,
599                help_data: h,
600            },
601        )),
602        Err(r) => Err(r),
603    }
604}
605
606fn array_constructor_call(s: Span) -> IResult<Span, Lang> {
607    let res = (
608        pascal_case,
609        tag(":["),
610        multispace0,
611        values,
612        terminated(tag("]"), multispace0),
613    )
614        .parse(s);
615    match res {
616        Ok((s, ((name, h), _, _, elems, _))) => Ok((
617            s,
618            Lang::ArrayConstructorCall {
619                type_name: name,
620                elements: elems,
621                help_data: h,
622            },
623        )),
624        Err(r) => Err(r),
625    }
626}
627
628fn record_identifier(s: Span) -> IResult<Span, Span> {
629    alt((tag("record"), tag("object"), tag("list"), tag(":"))).parse(s)
630}
631
632pub fn record(s: Span) -> IResult<Span, Lang> {
633    let res = (
634        opt(record_identifier),
635        terminated(alt((tag("{"), tag("("))), multispace0),
636        many0(argument_val),
637        terminated(alt((tag("}"), tag(")"))), multispace0),
638    )
639        .parse(s);
640    match res {
641        Ok((s, (Some(start), _, args, _))) => Ok((
642            s,
643            Lang::List {
644                value: args.clone(),
645                help_data: start.into(),
646            },
647        )),
648        Ok((_s, (None, _ob, args, _))) => {
649            if args.is_empty() {
650                panic!("Error: the scope shouldn't be empty")
651            } else {
652                eprintln!("{}", _s);
653                panic!("You forgot to put a record identifier before the bracket: ':{{...}}'");
654            }
655        }
656        Err(r) => Err(r),
657    }
658}
659
660fn pascal_case_helper(s: Span) -> IResult<Span, (String, HelpData)> {
661    let res = (one_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), alpha1).parse(s);
662    match res {
663        Ok((s, (t1, t2))) => Ok((s.clone(), (format!("{}{}", t1, t2), s.into()))),
664        Err(r) => Err(r),
665    }
666}
667
668fn pascal_case(s: Span) -> IResult<Span, (String, HelpData)> {
669    pascal_case_helper.parse(s)
670}
671
672fn union_constructor(s: Span) -> IResult<Span, Lang> {
673    let res = (
674        pascal_case,
675        terminated(tag("."), multispace0),
676        pascal_case,
677        opt((
678            terminated(tag(":"), multispace0),
679            terminated(tag("{"), multispace0),
680            many0(argument_val),
681            terminated(tag("}"), multispace0),
682        )),
683    )
684        .parse(s);
685    match res {
686        Ok((s, ((union_name, h), _, (variant_name, _), None))) => Ok((
687            s,
688            Lang::UnionConstructor {
689                union_name,
690                variant_name,
691                fields: vec![],
692                help_data: h,
693            },
694        )),
695        Ok((s, ((union_name, h), _, (variant_name, _), Some((_, _, fields, _))))) => Ok((
696            s,
697            Lang::UnionConstructor {
698                union_name,
699                variant_name,
700                fields,
701                help_data: h,
702            },
703        )),
704        Err(r) => Err(r),
705    }
706}
707
708fn parenthese_value(s: Span) -> IResult<Span, Lang> {
709    delimited(
710        terminated(tag("("), multispace0),
711        parse_elements,
712        terminated(tag(")"), multispace0),
713    )
714    .parse(s)
715}
716
717pub fn tag_exp(s: Span) -> IResult<Span, Lang> {
718    let res = terminated((tag("."), pascal_case, opt(parenthese_value)), multispace0).parse(s);
719    match res {
720        Ok((s, (dot, (n, _h), None))) => Ok((
721            s,
722            Lang::Tag {
723                name: n,
724                value: Box::new(Lang::Empty(dot.clone().into())),
725                help_data: dot.into(),
726            },
727        )),
728        Ok((s, (dot, (n, _h), Some(val)))) => Ok((
729            s,
730            Lang::Tag {
731                name: n,
732                value: Box::new(val),
733                help_data: dot.into(),
734            },
735        )),
736        Err(r) => Err(r),
737    }
738}
739
740fn dotdotdot(s: Span) -> IResult<Span, Lang> {
741    let res = terminated(tag("..."), multispace0).parse(s);
742    match res {
743        Ok((s, d)) => Ok((s, Lang::Empty(d.into()))),
744        Err(r) => Err(r),
745    }
746}
747
748fn else_exp(s: Span) -> IResult<Span, Lang> {
749    let res = (
750        terminated(tag("else"), multispace0),
751        terminated(tag("{"), multispace0),
752        parse_elements,
753        terminated(tag("}"), multispace0),
754    )
755        .parse(s);
756    match res {
757        Ok((s, (_else, _o, exp, _c))) => Ok((s, exp)),
758        Err(r) => Err(r),
759    }
760}
761
762fn else_if_exp(s: Span) -> IResult<Span, Lang> {
763    preceded(terminated(tag("else"), multispace1), if_exp).parse(s)
764}
765
766fn if_exp(s: Span) -> IResult<Span, Lang> {
767    let res = (
768        terminated(tag("if"), multispace0),
769        terminated(tag("("), multispace0),
770        parse_elements,
771        terminated(tag(")"), multispace0),
772        terminated(tag("{"), multispace0),
773        parse_elements,
774        terminated(tag("}"), multispace0),
775        opt(alt((else_if_exp, else_exp))),
776    )
777        .parse(s);
778    match res {
779        Ok((s, (_if, _op, cond, _cp, _o, exp, _c, els))) => Ok((
780            s,
781            Lang::If {
782                condition: Box::new(cond),
783                if_block: Box::new(exp),
784                else_block: Box::new(els.unwrap_or(Lang::Empty(HelpData::default()))),
785                help_data: _if.into(),
786            },
787        )),
788        Err(r) => Err(r),
789    }
790}
791
792/// Parse a tag pattern with a variable binding in parentheses: `.Some(a)`
793fn tag_pattern_with_var(s: Span) -> IResult<Span, Lang> {
794    let res = (
795        tag("."),
796        pascal_case,
797        delimited(
798            terminated(tag("("), multispace0),
799            variable2,
800            terminated(tag(")"), multispace0),
801        ),
802    )
803        .parse(s);
804    match res {
805        Ok((s, (dot, (n, _h), var))) => Ok((
806            s,
807            Lang::Tag {
808                name: n,
809                value: Box::new(var),
810                help_data: dot.into(),
811            },
812        )),
813        Err(r) => Err(r),
814    }
815}
816
817/// Parse a tag pattern without binding: `.None`
818fn tag_pattern_no_var(s: Span) -> IResult<Span, Lang> {
819    let res = (tag("."), pascal_case).parse(s);
820    match res {
821        Ok((s, (dot, (n, _h)))) => Ok((
822            s,
823            Lang::Tag {
824                name: n,
825                value: Box::new(Lang::Empty(dot.clone().into())),
826                help_data: dot.into(),
827            },
828        )),
829        Err(r) => Err(r),
830    }
831}
832
833/// Parse a wildcard pattern: `_`
834fn wildcard_pattern(s: Span) -> IResult<Span, Lang> {
835    let res = terminated(tag("_"), multispace0).parse(s);
836    match res {
837        Ok((s, underscore)) => Ok((
838            s,
839            Lang::Variable {
840                name: "_".to_string(),
841                is_opaque: false,
842                related_type: builder::empty_type(),
843                help_data: underscore.into(),
844            },
845        )),
846        Err(r) => Err(r),
847    }
848}
849
850/// Parse a type pattern with a variable binding: `x as int`, `y as bool`, etc.
851fn type_pattern(s: Span) -> IResult<Span, Lang> {
852    let res = (
853        terminated(variable_exp, multispace0),
854        terminated(tag("as"), multispace1),
855        terminated(primitive_types, multispace0),
856    )
857        .parse(s);
858    match res {
859        Ok((s, ((name, h), _as, typ))) => Ok((
860            s,
861            Lang::TypePattern {
862                variable_name: name,
863                matched_type: typ,
864                help_data: h,
865            },
866        )),
867        Err(r) => Err(r),
868    }
869}
870
871/// Parse a match pattern: `.Some(a)`, `.None`, `x as int`, `:{nom: n}`, `:{a, b}`, `_`, or a variable
872fn match_pattern(s: Span) -> IResult<Span, Lang> {
873    terminated(
874        alt((
875            tag_pattern_with_var,
876            tag_pattern_no_var,
877            record,
878            tuple_exp,
879            type_pattern,
880            wildcard_pattern,
881            variable2,
882        )),
883        multispace0,
884    )
885    .parse(s)
886}
887
888/// Parse a pattern branch: `pattern => expression,`
889fn pattern_branch(s: Span) -> IResult<Span, (Lang, Box<Lang>)> {
890    let res = (
891        terminated(match_pattern, multispace0),
892        terminated(tag("=>"), multispace0),
893        terminated(parse_elements, multispace0),
894        opt(terminated(tag(","), multispace0)),
895    )
896        .parse(s);
897    match res {
898        Ok((s, (pat, _arr, lang, _vir))) => Ok((s, (pat, Box::new(lang)))),
899        Err(r) => Err(r),
900    }
901}
902
903/// Parse a match expression with pattern matching:
904/// `match expr { .Some(a) => a, .None => 0, _ => default }`
905fn match_exp(s: Span) -> IResult<Span, Lang> {
906    let res = (
907        terminated(tag("match"), multispace1),
908        terminated(alt((scope, variable2)), multispace0),
909        terminated(tag("{"), multispace0),
910        many1(pattern_branch),
911        terminated(tag("}"), multispace0),
912    )
913        .parse(s);
914    match res {
915        Ok((s, (_m, exp, _o, bs, _c))) => Ok((
916            s,
917            Lang::Match {
918                target: Box::new(exp),
919                branches: bs,
920                help_data: _m.into(),
921            },
922        )),
923        Err(r) => Err(r),
924    }
925}
926
927pub fn tuple_exp(s: Span) -> IResult<Span, Lang> {
928    let res = (
929        terminated(alt((tag("list"), tag(":"))), multispace0),
930        terminated(alt((tag("{"), tag("("))), multispace0),
931        values,
932        terminated(alt((tag("}"), tag(")"))), multispace0),
933    )
934        .parse(s);
935    match res {
936        Ok((s, (id, _op, vals, _cl))) => Ok((
937            s,
938            Lang::Tuple {
939                value: vals,
940                help_data: id.into(),
941            },
942        )),
943        Err(r) => Err(r),
944    }
945}
946
947fn int_or_var(s: Span) -> IResult<Span, Lang> {
948    alt((integer, variable2)).parse(s)
949}
950
951fn create_range(params: &[Lang]) -> Lang {
952    if params.len() == 2 {
953        Lang::FunctionApp {
954            identifier: Box::new(Var::from_name("seq").to_language()),
955            arguments: vec![
956                params[0].clone(),
957                params[1].clone(),
958                Lang::Integer {
959                    value: 1,
960                    help_data: HelpData::default(),
961                },
962            ],
963            help_data: params.to_vec().into(),
964        }
965    } else {
966        Lang::FunctionApp {
967            identifier: Box::new(Var::from_name("seq").to_language()),
968            arguments: vec![params[0].clone(), params[1].clone(), params[2].clone()],
969            help_data: params.to_vec().into(),
970        }
971    }
972}
973
974fn range(s: Span) -> IResult<Span, Lang> {
975    let res = (
976        int_or_var,
977        tag(":"),
978        opt(terminated(int_or_var, tag(":"))),
979        int_or_var,
980    )
981        .parse(s);
982    //from_name().to_language()
983    match res {
984        Ok((s, (iv1, _sep, None, iv2))) => Ok((s, create_range(&[iv1.clone(), iv2.clone()]))),
985        Ok((s, (iv1, _sep, Some(iv0), iv2))) => {
986            Ok((s, create_range(&[iv1.clone(), iv2.clone(), iv0.clone()])))
987        }
988        Err(r) => Err(r),
989    }
990}
991
992fn function_application2(s: Span) -> IResult<Span, Lang> {
993    let res = recognize(function_application).parse(s);
994    match res {
995        Ok((s, fun_app)) => Ok((
996            s,
997            Lang::Exp {
998                value: fun_app.to_string(),
999                help_data: fun_app.into(),
1000            },
1001        )),
1002        Err(r) => Err(r),
1003    }
1004}
1005
1006fn dot_variable(s: Span) -> IResult<Span, Lang> {
1007    let res = preceded(tag("."), variable2).parse(s);
1008    match res {
1009        Ok((
1010            s,
1011            Lang::Variable {
1012                name: n,
1013                is_opaque: b,
1014                related_type: c,
1015                help_data: d,
1016            },
1017        )) => Ok((
1018            s,
1019            Lang::Variable {
1020                name: format!(".{}", n),
1021                is_opaque: b,
1022                related_type: c,
1023                help_data: d,
1024            },
1025        )),
1026        Ok((_s, _)) => todo!(),
1027        Err(r) => Err(r),
1028    }
1029}
1030
1031fn element_operator2(s: Span) -> IResult<Span, (Lang, Op)> {
1032    let res = (
1033        opt(op),
1034        alt((
1035            function_application2,
1036            null_value,
1037            number,
1038            integer,
1039            chars,
1040            boolean,
1041            variable2,
1042            dot_variable,
1043        )),
1044    )
1045        .parse(s);
1046    match res {
1047        Ok((s, (Some(ope), ele))) => Ok((s, (ele, ope))),
1048        Ok((s, (None, ele))) => Ok((s.clone(), (ele, Op::Empty(s.into())))),
1049        Err(r) => Err(r),
1050    }
1051}
1052
1053fn vectorial_bloc(s: Span) -> IResult<Span, Lang> {
1054    let res = (
1055        terminated(tag("@{"), multispace0),
1056        recognize(many1(element_operator2)),
1057        terminated(tag("}@"), multispace0),
1058    )
1059        .parse(s);
1060    match res {
1061        Ok((s, (_start, bloc, _end))) => Ok((
1062            s,
1063            Lang::VecBlock {
1064                value: bloc.fragment().to_string(),
1065                help_data: bloc.into(),
1066            },
1067        )),
1068        Err(r) => Err(r),
1069    }
1070}
1071
1072fn lambda(s: Span) -> IResult<Span, Lang> {
1073    let res = (
1074        tag("\\"),
1075        terminated(tag("("), multispace0),
1076        many0(terminated(variable, opt((tag(","), multispace0)))),
1077        terminated(tag(")"), multispace0),
1078        parse_elements,
1079    )
1080        .parse(s);
1081    match res {
1082        Ok((s, (start, _, v, _, body))) => Ok((
1083            s,
1084            Lang::Lambda {
1085                parameters: v.iter().map(|(var, _)| var).cloned().collect(),
1086                body: Box::new(body.clone()),
1087                help_data: start.into(),
1088            },
1089        )),
1090        Err(r) => Err(r),
1091    }
1092}
1093
1094fn not_exp(s: Span) -> IResult<Span, Lang> {
1095    let res = (
1096        tag("!"),
1097        alt((
1098            tag_exp,
1099            range,
1100            lambda,
1101            boolean,
1102            number,
1103            integer,
1104            chars,
1105            match_exp,
1106            if_exp,
1107            dotdotdot,
1108            vector,
1109            record,
1110            r_function,
1111            function,
1112            tuple_exp,
1113            function_application,
1114            array_indexing,
1115            variable2,
1116            scope,
1117            array,
1118        )),
1119    )
1120        .parse(s);
1121    match res {
1122        Ok((s, (not_op, lang))) => Ok((
1123            s,
1124            Lang::Not {
1125                value: Box::new(lang),
1126                help_data: not_op.into(),
1127            },
1128        )),
1129        Err(r) => Err(r),
1130    }
1131}
1132
1133fn array_variant(s: Span) -> IResult<Span, Lang> {
1134    alt((vector, sequence)).parse(s)
1135}
1136
1137fn js_block(s: Span) -> IResult<Span, Lang> {
1138    let res = (terminated(tag("JS"), multispace0), scope).parse(s);
1139
1140    match res {
1141        Ok((s, (js, body))) => Ok((s, Lang::JSBlock(Box::new(body), 0, js.into()))),
1142        Err(r) => Err(r),
1143    }
1144}
1145
1146fn primitive(s: Span) -> IResult<Span, Lang> {
1147    alt((null_value, na_value, boolean, number, integer, chars)).parse(s)
1148}
1149
1150pub fn return_exp(s: Span) -> IResult<Span, Lang> {
1151    let res = terminated(
1152        delimited(tag("return "), parse_elements, tag(";")),
1153        multispace0,
1154    )
1155    .parse(s);
1156    match res {
1157        Ok((s, el)) => Ok((
1158            s,
1159            Lang::Return {
1160                value: Box::new(el.clone()),
1161                help_data: el.into(),
1162            },
1163        )),
1164        Err(r) => Err(r),
1165    }
1166}
1167
1168pub fn break_exp(s: Span) -> IResult<Span, Vec<Lang>> {
1169    let res = tag("break;").parse(s);
1170    match res {
1171        Ok((s, el)) => Ok((s, vec![Lang::Break(el.into())])),
1172        Err(r) => Err(r),
1173    }
1174}
1175
1176// main
1177pub fn single_element(s: Span) -> IResult<Span, Lang> {
1178    alt((
1179        alt((
1180            not_exp,
1181            tag_exp,
1182            union_constructor,
1183            range,
1184            lambda,
1185            primitive,
1186            js_block,
1187            return_exp,
1188            match_exp,
1189            if_exp,
1190            dotdotdot,
1191            array_variant,
1192        )),
1193        alt((
1194            dataframe_exp,
1195            array_constructor_call,
1196            constructor_call,
1197            record,
1198            r_function,
1199            function,
1200            tuple_exp,
1201            function_application,
1202            array_indexing,
1203            variable2,
1204            scope,
1205            array,
1206        )),
1207    ))
1208    .parse(s)
1209}
1210
1211pub fn scope(s: Span) -> IResult<Span, Lang> {
1212    let res = (
1213        terminated(alt((tag("("), tag("{"))), multispace0),
1214        opt(base_parse),
1215        terminated(
1216            preceded(multispace0, alt((tag(")"), tag("}")))),
1217            multispace0,
1218        ),
1219    )
1220        .parse(s);
1221    match res {
1222        Ok((s, (open, Some(v), _))) if v.is_empty() => Ok((
1223            s,
1224            Lang::Scope {
1225                body: vec![],
1226                help_data: open.into(),
1227            },
1228        )),
1229        Ok((s, (_, Some(v), _))) => Ok((
1230            s,
1231            Lang::Scope {
1232                body: v.clone(),
1233                help_data: v.into(),
1234            },
1235        )),
1236        Ok((s, (open, None, _))) => Ok((
1237            s,
1238            Lang::Scope {
1239                body: vec![],
1240                help_data: open.into(),
1241            },
1242        )),
1243        Err(r) => Err(r),
1244    }
1245}
1246
1247fn element_operator_token(s: Span) -> IResult<Span, LangToken> {
1248    match op.parse(s) {
1249        Ok((s, op)) => Ok((s, LangToken::Operator(op))),
1250        Err(r) => Err(r),
1251    }
1252}
1253
1254fn single_element_token(s: Span) -> IResult<Span, LangToken> {
1255    match single_element.parse(s) {
1256        Ok((s, op)) => Ok((s, LangToken::Expression(op))),
1257        Err(r) => Err(r),
1258    }
1259}
1260
1261fn as_excl_operator_token(s: Span) -> IResult<Span, LangToken> {
1262    let res = terminated(tag("as!"), multispace0).parse(s);
1263    match res {
1264        Ok((s, tok)) => Ok((s, LangToken::Operator(Op::AsExcl(tok.into())))),
1265        Err(r) => Err(r),
1266    }
1267}
1268
1269pub fn elements(s: Span) -> IResult<Span, Lang> {
1270    let res = many1(alt((as_excl_operator_token, single_element_token, element_operator_token))).parse(s);
1271    match res {
1272        Ok((s, v)) => {
1273            if v.len() == 1 {
1274                Ok((s, v[0].clone().into()))
1275            } else {
1276                Ok((s, VectorPriority::from(v).run()))
1277            }
1278        }
1279        Err(r) => Err(r),
1280    }
1281}
1282
1283// main
1284pub fn parse_elements(s: Span) -> IResult<Span, Lang> {
1285    alt((vectorial_bloc, elements)).parse(s)
1286}
1287
1288#[cfg(test)]
1289mod tests {
1290    use super::*;
1291    use crate::utils::fluent_parser::FluentParser;
1292
1293    #[test]
1294    #[should_panic]
1295    fn test_empty_scope() {
1296        let _ = "{  }".parse::<Lang>();
1297    }
1298
1299    #[test]
1300    fn test_function_with_empty_scope3() {
1301        let res = simple_function("fn(): int { 5 }".into()).unwrap().1;
1302        assert_eq!(res.simple_print(), "Function");
1303    }
1304
1305    #[test]
1306    fn test_variable1() {
1307        let res = variable_exp("hello".into()).unwrap().1 .0;
1308        assert_eq!(res, "hello", "Should return the variable name 'hello'");
1309    }
1310
1311    #[test]
1312    fn test_simple_variable1() {
1313        let res = variable_exp("hello".into()).unwrap().1 .0;
1314        assert_eq!(res, "hello", "Should return the variable name 'hello'");
1315    }
1316
1317    #[test]
1318    fn test_addition1() {
1319        let res = "1 + 2".parse::<Lang>().unwrap();
1320        dbg!(&res);
1321        assert_eq!(res.simple_print(), "Operator", "Should parse 1 + 2");
1322    }
1323
1324    #[test]
1325    fn test_addition2() {
1326        let res = "1 + 2 + 3".parse::<Lang>().unwrap();
1327        dbg!(&res);
1328        assert_eq!(res.simple_print(), "Operator", "Should parse 1 + 2 + 3");
1329    }
1330
1331    #[test]
1332    fn test_multiplication1() {
1333        let res = "1 + 2 * 3".parse::<Lang>().unwrap();
1334        dbg!(&res);
1335        assert_eq!(
1336            res.simple_print(),
1337            "Operator",
1338            "Should put multiplication first 1 + 2 * 3"
1339        );
1340    }
1341
1342    #[test]
1343    fn test_multiplication2() {
1344        let res = "1 * 2 + 3".parse::<Lang>().unwrap();
1345        dbg!(&res);
1346        assert_eq!(
1347            res.simple_print(),
1348            "Operator",
1349            "Should put multiplication first 1 * 2 + 3"
1350        );
1351    }
1352
1353    #[test]
1354    fn test_multiplication3() {
1355        let res = "1 * 2 + 3 * 4".parse::<Lang>().unwrap();
1356        dbg!(&res);
1357        assert_eq!(
1358            res.simple_print(),
1359            "Operator",
1360            "Should put multiplication first 1 * 2 + 3 * 4"
1361        );
1362    }
1363
1364    #[test]
1365    fn test_accessor1() {
1366        let res = "3 + personne$age ".parse::<Lang>().unwrap();
1367        dbg!(&res);
1368        assert_eq!(
1369            res.simple_print(),
1370            "Operator",
1371            "Should put multiplication first 1 * 2 + 3 * 4"
1372        );
1373    }
1374
1375    #[test]
1376    fn test_and1() {
1377        let res = "true & true".parse::<Lang>().unwrap();
1378        dbg!(&res);
1379        assert_eq!(res.simple_print(), "Operator", "Should accept '&&'");
1380    }
1381
1382    #[test]
1383    fn test_array_indexing0() {
1384        let res = array_indexing("name[1, 2, 3]".into()).unwrap().1;
1385        dbg!(&res);
1386        assert!(true);
1387    }
1388
1389    #[test]
1390    fn test_array_indexing() {
1391        let fp = FluentParser::new().push("name[1, 2, 3]").parse_next();
1392        println!("fp: {}", fp);
1393        assert!(true);
1394    }
1395
1396    #[test]
1397    fn test_quoted_variable() {
1398        let res = quoted_variable("`+`".into()).unwrap().1;
1399        assert_eq!(res.0, "`+`");
1400    }
1401
1402    #[test]
1403    fn test_uniform_function_call() {
1404        let res = FluentParser::new().push("true.not()").parse_next();
1405        dbg!(&res.next_code());
1406        assert!(true);
1407    }
1408
1409    #[test]
1410    fn test_key_value1() {
1411        let res = key_value("sep = '3'".into()).unwrap().1;
1412        dbg!(&res);
1413        assert!(true);
1414    }
1415
1416    #[test]
1417    fn test_empty_char0() {
1418        let res = single_element("''".into()).unwrap().1;
1419        dbg!(&res);
1420        assert!(true);
1421    }
1422
1423    #[test]
1424    fn test_empty_char1() {
1425        let res = primitive("''".into()).unwrap().1;
1426        dbg!(&res);
1427        assert!(true);
1428    }
1429
1430    #[test]
1431    fn test_empty_char2() {
1432        let res = chars("''".into()).unwrap().1;
1433        dbg!(&res);
1434        assert!(true);
1435    }
1436
1437    // ==================== Null Tests ====================
1438
1439    #[test]
1440    fn test_null_value_lowercase() {
1441        let res = null_value("null ".into()).unwrap().1;
1442        assert_eq!(res.simple_print(), "Null");
1443    }
1444
1445    #[test]
1446    fn test_null_value_uppercase() {
1447        let res = null_value("NULL ".into()).unwrap().1;
1448        assert_eq!(res.simple_print(), "Null");
1449    }
1450
1451    #[test]
1452    fn test_null_via_primitive() {
1453        let res = primitive("null ".into()).unwrap().1;
1454        assert_eq!(res.simple_print(), "Null");
1455    }
1456
1457    #[test]
1458    fn test_null_via_single_element() {
1459        let res = single_element("null ".into()).unwrap().1;
1460        assert_eq!(res.simple_print(), "Null");
1461    }
1462
1463    #[test]
1464    fn test_null_parse_lang() {
1465        let res = "null".parse::<Lang>().unwrap();
1466        assert_eq!(res.simple_print(), "Null");
1467    }
1468
1469    #[test]
1470    fn test_null_type_check() {
1471        let fp = FluentParser::new()
1472            .push("let x: null <- null;")
1473            .parse_type_next()
1474            .push("x")
1475            .parse_next();
1476        assert_eq!(fp.get_last_type(), crate::utils::builder::null_type());
1477    }
1478
1479    // ==================== Match Pattern Tests ====================
1480
1481    #[test]
1482    fn test_match_pattern_tag_with_binding() {
1483        let input = "match x { .Some(a) => a, .None => 0 }";
1484        let res = match_exp(input.into()).unwrap().1;
1485        dbg!(&res);
1486        assert_eq!(res.simple_print(), "Match");
1487    }
1488
1489    #[test]
1490    fn test_match_pattern_with_wildcard() {
1491        let input = "match x { .Some(a) => a, _ => 0 }";
1492        let res = match_exp(input.into()).unwrap().1;
1493        dbg!(&res);
1494        assert_eq!(res.simple_print(), "Match");
1495    }
1496
1497    #[test]
1498    fn test_match_pattern_tag_without_binding() {
1499        let input = "match x { .None => 7 }";
1500        let res = match_exp(input.into()).unwrap().1;
1501        assert_eq!(res.simple_print(), "Match");
1502    }
1503
1504    #[test]
1505    fn test_match_pattern_multiple_branches() {
1506        let input = "match value { .Some(a) => a + 1, .None => 0, _ => 9 }";
1507        let res = match_exp(input.into()).unwrap().1;
1508        assert_eq!(res.simple_print(), "Match");
1509        // Verify we have 3 branches
1510        if let Lang::Match { branches, .. } = &res {
1511            assert_eq!(branches.len(), 3, "Should have 3 branches");
1512        } else {
1513            panic!("Expected Match variant");
1514        }
1515    }
1516
1517    #[test]
1518    fn test_match_pattern_via_single_element() {
1519        let input = "match x { .Some(a) => a, .None => 0 } ";
1520        let res = single_element(input.into()).unwrap().1;
1521        assert_eq!(res.simple_print(), "Match");
1522    }
1523
1524    #[test]
1525    fn test_match_pattern_branch_tag_with_var() {
1526        let input = ".Some(a) => a + 1, ";
1527        let res = pattern_branch(input.into()).unwrap().1;
1528        let (pattern, _body) = res;
1529        assert_eq!(pattern.simple_print(), "Tag");
1530    }
1531
1532    #[test]
1533    fn test_match_pattern_branch_wildcard() {
1534        let input = "_ => 42 ";
1535        let res = pattern_branch(input.into()).unwrap().1;
1536        let (pattern, _body) = res;
1537        assert_eq!(pattern.simple_print(), "Variable(_)");
1538    }
1539
1540    #[test]
1541    fn test_match_pattern_branch_tag_no_binding() {
1542        let input = ".None => 7, ";
1543        let res = pattern_branch(input.into()).unwrap().1;
1544        let (pattern, body) = res;
1545        assert_eq!(pattern.simple_print(), "Tag");
1546        assert_eq!(body.simple_print(), "Integer");
1547    }
1548
1549    #[test]
1550    fn test_wildcard_pattern() {
1551        let input = "_ ";
1552        let res = wildcard_pattern(input.into()).unwrap().1;
1553        assert_eq!(res.simple_print(), "Variable(_)");
1554    }
1555
1556    #[test]
1557    fn test_tag_pattern_with_var() {
1558        let input = ".Some(a)";
1559        let res = tag_pattern_with_var(input.into()).unwrap().1;
1560        assert_eq!(res.simple_print(), "Tag");
1561        if let Lang::Tag {
1562            name, value: inner, ..
1563        } = &res
1564        {
1565            assert_eq!(name, "Some");
1566            assert_eq!(inner.simple_print(), "Variable(a)");
1567        } else {
1568            panic!("Expected Tag variant");
1569        }
1570    }
1571
1572    #[test]
1573    fn test_tag_pattern_no_var() {
1574        let input = ".None ";
1575        let res = tag_pattern_no_var(input.into()).unwrap().1;
1576        assert_eq!(res.simple_print(), "Tag");
1577        if let Lang::Tag {
1578            name, value: inner, ..
1579        } = &res
1580        {
1581            assert_eq!(name, "None");
1582            assert_eq!(inner.simple_print(), "Empty");
1583        } else {
1584            panic!("Expected Tag variant");
1585        }
1586    }
1587
1588    #[test]
1589    fn test_match_pattern_multiline() {
1590        let input = "match result {
1591            .Some(value) => value + 1,
1592            .None => 0,
1593            _ => 99
1594        } ";
1595        let res = match_exp(input.into()).unwrap().1;
1596        assert_eq!(res.simple_print(), "Match");
1597        if let Lang::Match { branches, .. } = &res {
1598            assert_eq!(branches.len(), 3);
1599        } else {
1600            panic!("Expected Match variant");
1601        }
1602    }
1603
1604    // ==================== Type Pattern Tests ====================
1605
1606    #[test]
1607    fn test_type_pattern_int() {
1608        let input = "x as int ";
1609        let res = type_pattern(input.into()).unwrap().1;
1610        assert!(
1611            res.simple_print().starts_with("TypePattern"),
1612            "Should parse 'x as int' as TypePattern"
1613        );
1614        if let Lang::TypePattern {
1615            variable_name: name,
1616            ..
1617        } = &res
1618        {
1619            assert_eq!(name, "x");
1620        } else {
1621            panic!("Expected TypePattern variant");
1622        }
1623    }
1624
1625    #[test]
1626    fn test_type_pattern_bool() {
1627        let input = "y as bool ";
1628        let res = type_pattern(input.into()).unwrap().1;
1629        if let Lang::TypePattern {
1630            variable_name: name,
1631            ..
1632        } = &res
1633        {
1634            assert_eq!(name, "y");
1635        } else {
1636            panic!("Expected TypePattern variant");
1637        }
1638    }
1639
1640    #[test]
1641    fn test_type_pattern_num() {
1642        let input = "val as num ";
1643        let res = type_pattern(input.into()).unwrap().1;
1644        if let Lang::TypePattern {
1645            variable_name: name,
1646            ..
1647        } = &res
1648        {
1649            assert_eq!(name, "val");
1650        } else {
1651            panic!("Expected TypePattern variant");
1652        }
1653    }
1654
1655    #[test]
1656    fn test_type_pattern_char() {
1657        let input = "s as char ";
1658        let res = type_pattern(input.into()).unwrap().1;
1659        if let Lang::TypePattern {
1660            variable_name: name,
1661            ..
1662        } = &res
1663        {
1664            assert_eq!(name, "s");
1665        } else {
1666            panic!("Expected TypePattern variant");
1667        }
1668    }
1669
1670    #[test]
1671    fn test_match_with_type_patterns() {
1672        let input = "match x { y as int => y + 1, z as bool => 0 } ";
1673        let res = match_exp(input.into()).unwrap().1;
1674        assert_eq!(res.simple_print(), "Match");
1675        if let Lang::Match { branches, .. } = &res {
1676            assert_eq!(branches.len(), 2, "Should have 2 branches");
1677            assert!(
1678                branches[0].0.simple_print().starts_with("TypePattern"),
1679                "First branch should be a TypePattern"
1680            );
1681            assert!(
1682                branches[1].0.simple_print().starts_with("TypePattern"),
1683                "Second branch should be a TypePattern"
1684            );
1685        } else {
1686            panic!("Expected Match variant");
1687        }
1688    }
1689
1690    #[test]
1691    fn test_match_mixed_tag_and_type_patterns() {
1692        let input = "match value {
1693            .Some(a) => a,
1694            x as int => x + 1,
1695            _ => 0
1696        } ";
1697        let res = match_exp(input.into()).unwrap().1;
1698        assert_eq!(res.simple_print(), "Match");
1699        if let Lang::Match { branches, .. } = &res {
1700            assert_eq!(branches.len(), 3, "Should have 3 branches");
1701            assert_eq!(branches[0].0.simple_print(), "Tag");
1702            assert!(branches[1].0.simple_print().starts_with("TypePattern"));
1703            assert_eq!(branches[2].0.simple_print(), "Variable(_)");
1704        } else {
1705            panic!("Expected Match variant");
1706        }
1707    }
1708
1709    #[test]
1710    fn test_type_pattern_in_match_pattern() {
1711        let input = "x as int ";
1712        let res = match_pattern(input.into()).unwrap().1;
1713        assert!(
1714            res.simple_print().starts_with("TypePattern"),
1715            "match_pattern should accept type patterns"
1716        );
1717    }
1718
1719    // ==================== List/Record Pattern Tests ====================
1720
1721    #[test]
1722    fn test_record_pattern_colon_syntax() {
1723        let input = ":{nom: n, age: a} ";
1724        let res = match_pattern(input.into()).unwrap().1;
1725        assert_eq!(
1726            res.simple_print(),
1727            "Record",
1728            "Should parse record pattern as Record"
1729        );
1730        if let Lang::List { value: fields, .. } = &res {
1731            assert_eq!(fields.len(), 2);
1732            assert_eq!(fields[0].get_argument(), "nom");
1733            assert_eq!(fields[1].get_argument(), "age");
1734        } else {
1735            panic!("Expected List variant");
1736        }
1737    }
1738
1739    #[test]
1740    fn test_record_pattern_list_syntax() {
1741        let input = "list(nom = n, age = a) ";
1742        let res = match_pattern(input.into()).unwrap().1;
1743        assert_eq!(res.simple_print(), "Record");
1744        if let Lang::List { value: fields, .. } = &res {
1745            assert_eq!(fields.len(), 2);
1746            assert_eq!(fields[0].get_argument(), "nom");
1747            assert_eq!(fields[1].get_argument(), "age");
1748        } else {
1749            panic!("Expected List variant");
1750        }
1751    }
1752
1753    #[test]
1754    fn test_match_with_record_pattern() {
1755        let input = "match x { :{nom: n, age: a} => a, _ => 0 } ";
1756        let res = match_exp(input.into()).unwrap().1;
1757        assert_eq!(res.simple_print(), "Match");
1758        if let Lang::Match { branches, .. } = &res {
1759            assert_eq!(branches.len(), 2, "Should have 2 branches");
1760            assert_eq!(
1761                branches[0].0.simple_print(),
1762                "Record",
1763                "First branch should be a Record pattern"
1764            );
1765            assert_eq!(branches[1].0.simple_print(), "Variable(_)");
1766        } else {
1767            panic!("Expected Match variant");
1768        }
1769    }
1770
1771    #[test]
1772    fn test_match_with_list_pattern() {
1773        let input = "match x { list(nom = n, age = a) => a, _ => 0 } ";
1774        let res = match_exp(input.into()).unwrap().1;
1775        assert_eq!(res.simple_print(), "Match");
1776        if let Lang::Match { branches, .. } = &res {
1777            assert_eq!(branches.len(), 2);
1778            assert_eq!(branches[0].0.simple_print(), "Record");
1779        } else {
1780            panic!("Expected Match variant");
1781        }
1782    }
1783
1784    #[test]
1785    fn test_match_mixed_record_tag_type_patterns() {
1786        let input = "match value {
1787            .Some(a) => a,
1788            :{nom: n, age: a} => a,
1789            x as int => x + 1,
1790            _ => 0
1791        } ";
1792        let res = match_exp(input.into()).unwrap().1;
1793        assert_eq!(res.simple_print(), "Match");
1794        if let Lang::Match { branches, .. } = &res {
1795            assert_eq!(branches.len(), 4);
1796            assert_eq!(branches[0].0.simple_print(), "Tag");
1797            assert_eq!(branches[1].0.simple_print(), "Record");
1798            assert!(branches[2].0.simple_print().starts_with("TypePattern"));
1799            assert_eq!(branches[3].0.simple_print(), "Variable(_)");
1800        } else {
1801            panic!("Expected Match variant");
1802        }
1803    }
1804
1805    #[test]
1806    fn test_record_pattern_single_field() {
1807        let input = ":{nom: n} ";
1808        let res = match_pattern(input.into()).unwrap().1;
1809        assert_eq!(res.simple_print(), "Record");
1810        if let Lang::List { value: fields, .. } = &res {
1811            assert_eq!(fields.len(), 1);
1812            assert_eq!(fields[0].get_argument(), "nom");
1813        } else {
1814            panic!("Expected List variant");
1815        }
1816    }
1817
1818    // ==================== Tuple Pattern Tests ====================
1819
1820    #[test]
1821    fn test_tuple_pattern_colon_syntax() {
1822        let input = ":{a, b, c} ";
1823        let res = match_pattern(input.into()).unwrap().1;
1824        assert_eq!(res.simple_print(), "Tuple");
1825        if let Lang::Tuple {
1826            value: elements, ..
1827        } = &res
1828        {
1829            assert_eq!(elements.len(), 3);
1830        } else {
1831            panic!("Expected Tuple variant");
1832        }
1833    }
1834
1835    #[test]
1836    fn test_tuple_pattern_list_syntax() {
1837        let input = "list(a, b, c) ";
1838        let res = match_pattern(input.into()).unwrap().1;
1839        assert_eq!(res.simple_print(), "Tuple");
1840        if let Lang::Tuple {
1841            value: elements, ..
1842        } = &res
1843        {
1844            assert_eq!(elements.len(), 3);
1845        } else {
1846            panic!("Expected Tuple variant");
1847        }
1848    }
1849
1850    #[test]
1851    fn test_tuple_pattern_two_elements() {
1852        let input = ":{x, y} ";
1853        let res = match_pattern(input.into()).unwrap().1;
1854        assert_eq!(res.simple_print(), "Tuple");
1855        if let Lang::Tuple {
1856            value: elements, ..
1857        } = &res
1858        {
1859            assert_eq!(elements.len(), 2);
1860        } else {
1861            panic!("Expected Tuple variant");
1862        }
1863    }
1864
1865    #[test]
1866    fn test_match_with_tuple_pattern() {
1867        let input = "match x { :{a, b, c} => a + c, _ => 0 } ";
1868        let res = match_exp(input.into()).unwrap().1;
1869        assert_eq!(res.simple_print(), "Match");
1870        if let Lang::Match { branches, .. } = &res {
1871            assert_eq!(branches.len(), 2);
1872            assert_eq!(branches[0].0.simple_print(), "Tuple");
1873            assert_eq!(branches[1].0.simple_print(), "Variable(_)");
1874        } else {
1875            panic!("Expected Match variant");
1876        }
1877    }
1878
1879    #[test]
1880    fn test_match_with_list_tuple_pattern() {
1881        let input = "match x { list(a, b, c) => a + c, _ => 0 } ";
1882        let res = match_exp(input.into()).unwrap().1;
1883        assert_eq!(res.simple_print(), "Match");
1884        if let Lang::Match { branches, .. } = &res {
1885            assert_eq!(branches.len(), 2);
1886            assert_eq!(branches[0].0.simple_print(), "Tuple");
1887        } else {
1888            panic!("Expected Match variant");
1889        }
1890    }
1891
1892    #[test]
1893    fn test_match_mixed_all_pattern_types() {
1894        let input = "match value {
1895            .Some(a) => a,
1896            :{nom: n, age: a} => a,
1897            :{x, y} => x + y,
1898            z as int => z + 1,
1899            _ => 0
1900        } ";
1901        let res = match_exp(input.into()).unwrap().1;
1902        assert_eq!(res.simple_print(), "Match");
1903        if let Lang::Match { branches, .. } = &res {
1904            assert_eq!(branches.len(), 5);
1905            assert_eq!(branches[0].0.simple_print(), "Tag");
1906            assert_eq!(branches[1].0.simple_print(), "Record");
1907            assert_eq!(branches[2].0.simple_print(), "Tuple");
1908            assert!(branches[3].0.simple_print().starts_with("TypePattern"));
1909            assert_eq!(branches[4].0.simple_print(), "Variable(_)");
1910        } else {
1911            panic!("Expected Match variant");
1912        }
1913    }
1914
1915    #[test]
1916    fn test_character_constructor_fn() {
1917        let input = "fn(name: char, attack: int, health: int): Character {\n    :{ name: name, attack: attack, health: health }\n}";
1918        let res = simple_function(input.into());
1919        match &res {
1920            Ok((remaining, _)) => {
1921                println!("SUCCESS, remaining: {:?}", **remaining);
1922                assert!(
1923                    remaining.is_empty(),
1924                    "Should consume entire input, remaining: {:?}",
1925                    **remaining
1926                );
1927            }
1928            Err(e) => panic!("Parse failed: {:?}", e),
1929        }
1930    }
1931
1932    #[test]
1933    fn test_scope_with_record_body() {
1934        let input = "{\n    :{ name: name, attack: attack, health: health }\n}";
1935        let res = scope(input.into());
1936        match &res {
1937            Ok((remaining, _)) => {
1938                println!("scope SUCCESS, remaining: {:?}", **remaining);
1939            }
1940            Err(e) => println!("scope FAILED: {:?}", e),
1941        }
1942        assert!(res.is_ok(), "scope should succeed");
1943    }
1944
1945    #[test]
1946    fn test_record_parse_directly() {
1947        use crate::processes::parsing::base_parse;
1948        let input = ":{ name: name, attack: attack, health: health }";
1949        let res = base_parse(input.into());
1950        println!(
1951            "base_parse result: {:?}",
1952            res.as_ref()
1953                .map(|(r, v): &(_, Vec<_>)| (*r.fragment(), v.len()))
1954        );
1955        assert!(res.is_ok());
1956        let (remaining, elems) = res.unwrap();
1957        println!("  remaining: {:?}", *remaining.fragment());
1958        println!("  elements count: {}", elems.len());
1959        for (i, el) in elems.iter().enumerate() {
1960            println!("  elem[{}]: {}", i, el.simple_print());
1961        }
1962    }
1963
1964    #[test]
1965    fn test_parse_elements_record() {
1966        let input = ":{ name: name, attack: attack, health: health }";
1967        let res = parse_elements(input.into());
1968        match &res {
1969            Ok((remaining, lang)) => println!(
1970                "parse_elements OK: {}, remaining: {:?}",
1971                lang.simple_print(),
1972                **remaining
1973            ),
1974            Err(e) => println!("parse_elements FAILED: {:?}", e),
1975        }
1976        assert!(res.is_ok(), "parse_elements should succeed on record");
1977    }
1978
1979    #[test]
1980    fn test_single_element_record() {
1981        let input = ":{ name: name, attack: attack, health: health }";
1982        let res = single_element(input.into());
1983        match &res {
1984            Ok((remaining, lang)) => println!(
1985                "single_element OK: {}, remaining: {:?}",
1986                lang.simple_print(),
1987                **remaining
1988            ),
1989            Err(e) => println!("single_element FAILED: {:?}", e),
1990        }
1991        assert!(res.is_ok(), "single_element should succeed on record");
1992    }
1993
1994    #[test]
1995    fn test_record_logic_inline() {
1996        let input = ":{ name: name, attack: attack, health: health }";
1997        let res = record(input.into());
1998        match &res {
1999            Ok((remaining, lang)) => println!(
2000                "record OK: {}, remaining: {:?}",
2001                lang.simple_print(),
2002                **remaining
2003            ),
2004            Err(e) => println!("record FAILED: {:?}", e),
2005        }
2006        assert!(res.is_ok(), "record should succeed");
2007    }
2008}