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