Skip to main content

typr_core/processes/parsing/
elements.rs

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