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
161pub 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 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 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
428fn 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
437pub 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 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
661fn 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
674enum ConstructorElement {
678 Field(Box<ArgumentValue>),
679 Spread(Vec<String>, String, HelpData),
680 RuntimeSpread(Box<Lang>),
681}
682
683fn 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
698fn 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 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
803enum RecordElement {
806 Field(Box<ArgumentValue>),
807 Spread(Box<Lang>),
808}
809
810fn 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
1000fn 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
1025fn 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
1041fn 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
1058fn 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
1079fn 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
1096fn 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
1111fn 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 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
1280fn 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
1310fn 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
1470pub 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
1585pub 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 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 #[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 #[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 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 #[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 #[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 #[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}