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