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