1use chumsky::Parser;
100use chumsky::error::Rich;
101use chumsky::prelude::*;
102use rust_decimal::Decimal;
103use std::fmt;
104use std::str::FromStr;
105
106#[derive(Debug, Clone, PartialEq)]
120pub enum Literal {
121 Null,
123 Boolean(bool),
125 String(String),
127 Number(Decimal),
129 Integer(i64),
131 Date(helios_fhir::PrecisionDate),
133 DateTime(helios_fhir::PrecisionDateTime),
135 Time(helios_fhir::PrecisionTime),
137 Quantity(Decimal, String),
139}
140
141#[derive(Debug, Clone, PartialEq)]
152pub enum Expression {
153 Term(Term),
155
156 Invocation(Box<Expression>, Invocation),
159
160 Indexer(Box<Expression>, Box<Expression>),
162
163 Polarity(char, Box<Expression>),
166
167 Multiplicative(Box<Expression>, String, Box<Expression>),
170
171 Additive(Box<Expression>, String, Box<Expression>),
174
175 Type(Box<Expression>, String, TypeSpecifier),
178
179 Union(Box<Expression>, Box<Expression>),
182
183 Inequality(Box<Expression>, String, Box<Expression>),
186
187 Equality(Box<Expression>, String, Box<Expression>),
190
191 Membership(Box<Expression>, String, Box<Expression>),
194
195 And(Box<Expression>, Box<Expression>),
198
199 Or(Box<Expression>, String, Box<Expression>),
202
203 Implies(Box<Expression>, Box<Expression>),
206
207 Lambda(Option<String>, Box<Expression>),
210
211 InstanceSelector(String, Vec<(String, Box<Expression>)>),
215}
216
217#[derive(Debug, Clone, PartialEq)]
231pub enum TypeSpecifier {
232 QualifiedIdentifier(String, Option<String>),
247}
248
249#[derive(Debug, Clone, PartialEq)]
259pub enum Term {
260 Invocation(Invocation),
263
264 Literal(Literal),
267
268 ExternalConstant(String),
271
272 Parenthesized(Box<Expression>),
275}
276
277#[derive(Debug, Clone, PartialEq)]
286pub enum Invocation {
287 Member(String),
290
291 Function(String, Vec<Expression>),
294
295 This,
298
299 Index,
302
303 Total,
306}
307
308#[derive(Debug, Clone, PartialEq)]
312pub struct ExprSpan {
313 pub position: usize,
314 pub length: usize,
315}
316
317#[derive(Debug, Clone)]
319pub struct SpannedExpression {
320 pub kind: SpannedExprKind,
321 pub span: ExprSpan,
322}
323
324#[derive(Debug, Clone)]
326pub enum SpannedExprKind {
327 Term(SpannedTerm),
328 Invocation(Box<SpannedExpression>, SpannedInvocation),
329 Indexer(Box<SpannedExpression>, Box<SpannedExpression>),
330 Polarity(char, Box<SpannedExpression>),
331 Multiplicative(Box<SpannedExpression>, String, Box<SpannedExpression>),
332 Additive(Box<SpannedExpression>, String, Box<SpannedExpression>),
333 Type(Box<SpannedExpression>, String, TypeSpecifier),
334 Union(Box<SpannedExpression>, Box<SpannedExpression>),
335 Inequality(Box<SpannedExpression>, String, Box<SpannedExpression>),
336 Equality(Box<SpannedExpression>, String, Box<SpannedExpression>),
337 Membership(Box<SpannedExpression>, String, Box<SpannedExpression>),
338 And(Box<SpannedExpression>, Box<SpannedExpression>),
339 Or(Box<SpannedExpression>, String, Box<SpannedExpression>),
340 Implies(Box<SpannedExpression>, Box<SpannedExpression>),
341 Lambda(Option<String>, Box<SpannedExpression>),
342 InstanceSelector(String, Vec<(String, Box<SpannedExpression>)>),
343}
344
345#[derive(Debug, Clone)]
346pub enum SpannedTerm {
347 Literal(Literal),
348 Invocation(SpannedInvocation),
349 ExternalConstant(String),
350 Parenthesized(Box<SpannedExpression>),
351}
352
353#[derive(Debug, Clone)]
354pub enum SpannedInvocation {
355 Member(String),
356 Function(String, Vec<SpannedExpression>),
357 This,
358 Index,
359 Total,
360}
361
362impl SpannedExpression {
363 pub fn to_expression(&self) -> Expression {
364 match &self.kind {
365 SpannedExprKind::Term(t) => Expression::Term(t.to_term()),
366 SpannedExprKind::Invocation(base, inv) => {
367 Expression::Invocation(Box::new(base.to_expression()), inv.to_invocation())
368 }
369 SpannedExprKind::Indexer(expr, idx) => Expression::Indexer(
370 Box::new(expr.to_expression()),
371 Box::new(idx.to_expression()),
372 ),
373 SpannedExprKind::Polarity(op, expr) => {
374 Expression::Polarity(*op, Box::new(expr.to_expression()))
375 }
376 SpannedExprKind::Multiplicative(l, op, r) => Expression::Multiplicative(
377 Box::new(l.to_expression()),
378 op.clone(),
379 Box::new(r.to_expression()),
380 ),
381 SpannedExprKind::Additive(l, op, r) => Expression::Additive(
382 Box::new(l.to_expression()),
383 op.clone(),
384 Box::new(r.to_expression()),
385 ),
386 SpannedExprKind::Type(expr, op, ts) => {
387 Expression::Type(Box::new(expr.to_expression()), op.clone(), ts.clone())
388 }
389 SpannedExprKind::Union(l, r) => {
390 Expression::Union(Box::new(l.to_expression()), Box::new(r.to_expression()))
391 }
392 SpannedExprKind::Inequality(l, op, r) => Expression::Inequality(
393 Box::new(l.to_expression()),
394 op.clone(),
395 Box::new(r.to_expression()),
396 ),
397 SpannedExprKind::Equality(l, op, r) => Expression::Equality(
398 Box::new(l.to_expression()),
399 op.clone(),
400 Box::new(r.to_expression()),
401 ),
402 SpannedExprKind::Membership(l, op, r) => Expression::Membership(
403 Box::new(l.to_expression()),
404 op.clone(),
405 Box::new(r.to_expression()),
406 ),
407 SpannedExprKind::And(l, r) => {
408 Expression::And(Box::new(l.to_expression()), Box::new(r.to_expression()))
409 }
410 SpannedExprKind::Or(l, op, r) => Expression::Or(
411 Box::new(l.to_expression()),
412 op.clone(),
413 Box::new(r.to_expression()),
414 ),
415 SpannedExprKind::Implies(l, r) => {
416 Expression::Implies(Box::new(l.to_expression()), Box::new(r.to_expression()))
417 }
418 SpannedExprKind::Lambda(param, expr) => {
419 Expression::Lambda(param.clone(), Box::new(expr.to_expression()))
420 }
421 SpannedExprKind::InstanceSelector(type_name, fields) => Expression::InstanceSelector(
422 type_name.clone(),
423 fields
424 .iter()
425 .map(|(name, expr)| (name.clone(), Box::new(expr.to_expression())))
426 .collect(),
427 ),
428 }
429 }
430}
431
432impl SpannedTerm {
433 pub fn to_term(&self) -> Term {
434 match self {
435 SpannedTerm::Literal(l) => Term::Literal(l.clone()),
436 SpannedTerm::Invocation(i) => Term::Invocation(i.to_invocation()),
437 SpannedTerm::ExternalConstant(s) => Term::ExternalConstant(s.clone()),
438 SpannedTerm::Parenthesized(e) => Term::Parenthesized(Box::new(e.to_expression())),
439 }
440 }
441}
442
443impl SpannedInvocation {
444 pub fn to_invocation(&self) -> Invocation {
445 match self {
446 SpannedInvocation::Member(s) => Invocation::Member(s.clone()),
447 SpannedInvocation::Function(name, args) => Invocation::Function(
448 name.clone(),
449 args.iter().map(|a| a.to_expression()).collect(),
450 ),
451 SpannedInvocation::This => Invocation::This,
452 SpannedInvocation::Index => Invocation::Index,
453 SpannedInvocation::Total => Invocation::Total,
454 }
455 }
456}
457
458impl fmt::Display for Literal {
459 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
460 match self {
461 Literal::Null => write!(f, "{{}}"),
462 Literal::Boolean(b) => write!(f, "{}", b),
463 Literal::String(s) => write!(f, "'{}'", s),
464 Literal::Number(d) => write!(f, "{}", d), Literal::Integer(n) => write!(f, "{}", n),
466 Literal::Date(d) => write!(f, "@{}", d.original_string()),
467 Literal::DateTime(dt) => write!(f, "@{}", dt.original_string()),
468 Literal::Time(t) => write!(f, "@T{}", t.original_string()),
469 Literal::Quantity(d, u) => write!(f, "{} '{}'", d, u), }
471 }
472}
473
474fn clean_backtick_identifier(id: &str) -> String {
476 if id.starts_with('`') && id.ends_with('`') && id.len() >= 3 {
477 id[1..id.len() - 1].to_string()
478 } else {
479 id.to_string()
480 }
481}
482
483fn combine_string_code_units(codes: Vec<u32>) -> Result<String, &'static str> {
488 let mut out = String::with_capacity(codes.len());
489 let mut i = 0;
490 while i < codes.len() {
491 let c = codes[i];
492 if (0xD800..=0xDBFF).contains(&c) {
493 if let Some(&lo) = codes.get(i + 1) {
494 if (0xDC00..=0xDFFF).contains(&lo) {
495 let scalar = 0x10000 + ((c - 0xD800) << 10) + (lo - 0xDC00);
496 match char::from_u32(scalar) {
497 Some(ch) => {
498 out.push(ch);
499 i += 2;
500 continue;
501 }
502 None => return Err("Invalid surrogate pair"),
503 }
504 }
505 }
506 return Err("Unpaired high surrogate in \\uXXXX escape");
507 }
508 if (0xDC00..=0xDFFF).contains(&c) {
509 return Err("Unpaired low surrogate in \\uXXXX escape");
510 }
511 match char::from_u32(c) {
512 Some(ch) => out.push(ch),
513 None => return Err("Invalid Unicode code point"),
514 }
515 i += 1;
516 }
517 Ok(out)
518}
519
520fn custom_padded<'src, T, P>(
548 parser: P,
549) -> impl Parser<'src, &'src str, T, extra::Err<Rich<'src, char>>> + Clone
550where
551 P: Parser<'src, &'src str, T, extra::Err<Rich<'src, char>>> + Clone,
552 T: Clone,
553{
554 let ws_or_comment = choice((
556 text::whitespace().at_least(1).ignored(),
558 just("//")
560 .then(any().and_is(text::newline().or(end()).not()).repeated())
561 .ignored(),
562 just("/*")
564 .then(any().and_is(just("*/").not()).repeated())
565 .then(just("*/"))
566 .ignored(),
567 ))
568 .repeated()
569 .ignored();
570
571 ws_or_comment
572 .then(parser)
573 .map(|(_, result)| result)
574 .then_ignore(ws_or_comment)
575}
576
577pub fn parser<'src>()
578-> impl Parser<'src, &'src str, Expression, extra::Err<Rich<'src, char>>> + Clone + 'src {
579 let esc = just('\\').ignore_then(choice((
583 just('`').to('`' as u32),
584 just('\'').to('\'' as u32),
585 just('\\').to('\\' as u32),
586 just('/').to('/' as u32),
587 just('f').to(0x000C_u32),
588 just('n').to('\n' as u32),
589 just('r').to('\r' as u32),
590 just('t').to('\t' as u32),
591 just('"').to('"' as u32),
592 just('u').ignore_then(
595 any()
596 .filter(|c: &char| c.is_ascii_hexdigit())
597 .repeated()
598 .exactly(4)
599 .collect::<String>()
600 .try_map(
601 |digits: String, span| match u32::from_str_radix(&digits, 16) {
602 Ok(code) => Ok(code),
603 Err(_) => Err(Rich::custom(span, "Invalid hex digits")),
604 },
605 ),
606 ),
607 )));
608
609 macro_rules! padded {
611 ($p:expr) => {
612 custom_padded($p)
613 };
614 }
615
616 let null = just('{').then(just('}')).to(Literal::Null);
621
622 let boolean = choice((
625 text::keyword("true").to(Literal::Boolean(true)),
626 text::keyword("false").to(Literal::Boolean(false)),
627 ))
628 .boxed();
629
630 let string = just('\'')
633 .ignore_then(
634 none_of("\\\'")
635 .map(|c: char| c as u32)
636 .or(esc)
637 .repeated()
638 .collect::<Vec<u32>>(),
639 )
640 .then_ignore(just('\''))
641 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)))
642 .map(Literal::String)
643 .boxed();
644
645 let integer = any()
651 .filter(|c: &char| c.is_ascii_digit())
652 .repeated()
653 .at_least(1) .collect::<String>()
655 .try_map(|digits: String, span| match i64::from_str(&digits) {
656 Ok(n) => Ok(Literal::Integer(n)),
657 Err(_) => Err(Rich::custom(span, format!("Invalid integer: {}", digits))),
658 });
659 let integer = padded!(integer); let number = any()
670 .filter(|c: &char| c.is_ascii_digit())
671 .repeated()
672 .at_least(1) .collect::<String>()
674 .then(just('.')) .then(
676 any()
677 .filter(|c: &char| c.is_ascii_digit())
678 .repeated()
679 .at_least(1) .collect::<String>(),
681 )
682 .try_map(|((i, _), d), span| {
683 let num_str = format!("{}.{}", i, d);
684 match Decimal::from_str(&num_str) {
685 Ok(decimal) => Ok(Literal::Number(decimal)),
686 Err(_) => Err(Rich::custom(span, format!("Invalid number: {}", num_str))),
687 }
688 })
689 .padded(); let time_format = any()
703 .filter(|c: &char| c.is_ascii_digit())
704 .repeated()
705 .at_least(2) .at_most(2)
707 .collect::<String>()
708 .then(
709 just(':') .ignore_then(
711 any()
712 .filter(|c: &char| c.is_ascii_digit())
713 .repeated()
714 .at_least(2) .at_most(2)
716 .collect::<String>(),
717 )
718 .then(
719 just(':') .ignore_then(
721 any()
722 .filter(|c: &char| c.is_ascii_digit())
723 .repeated()
724 .at_least(2) .at_most(2)
726 .collect::<String>(),
727 )
728 .then(
729 just('.') .ignore_then(
731 any()
732 .filter(|c: &char| c.is_ascii_digit())
733 .repeated()
734 .at_least(1) .at_most(3)
736 .collect::<String>(),
737 )
738 .or_not(),
739 )
740 .or_not(),
741 )
742 .or_not(),
743 )
744 .map(|(hours, rest_opt)| {
745 let mut result = hours;
747 if let Some((minutes, seconds_part)) = rest_opt {
748 result.push(':');
749 result.push_str(&minutes);
750
751 if let Some((seconds, milliseconds)) = seconds_part {
752 result.push(':');
753 result.push_str(&seconds);
754
755 if let Some(ms) = milliseconds {
757 result.push('.');
758 result.push_str(&ms);
759 }
760 }
761 }
762 result
763 });
764
765 let timezone_format = just('Z')
774 .to("Z".to_string()) .or(one_of("+-") .map(|c: char| c.to_string()) .then(
778 any()
779 .filter(|c: &char| c.is_ascii_digit())
780 .repeated()
781 .at_most(2) .at_least(2)
783 .collect::<String>(),
784 )
785 .then(just(':')) .then(
787 any()
788 .filter(|c: &char| c.is_ascii_digit())
789 .repeated()
790 .at_most(2) .at_least(2)
792 .collect::<String>(),
793 )
794 .map(|(((sign, hour), _), min)| format!("{}{}:{}", sign, hour, min)));
795
796 let date_format_str = any()
813 .filter(|c: &char| c.is_ascii_digit())
814 .repeated()
815 .exactly(4) .collect::<String>()
817 .then(
818 just('-') .ignore_then(
820 any()
821 .filter(|c: &char| c.is_ascii_digit())
822 .repeated()
823 .exactly(2) .collect::<String>()
825 .then(
826 just('-') .ignore_then(
828 any()
829 .filter(|c: &char| c.is_ascii_digit())
830 .repeated()
831 .exactly(2) .collect::<String>(),
833 )
834 .or_not(),
835 ),
836 )
837 .or_not(),
838 )
839 .map(|(year, month_part)| {
840 let mut date_str = year;
842
843 if let Some((month_str, day_part)) = month_part {
845 date_str.push('-');
846 date_str.push_str(&month_str);
847
848 if let Some(day_str) = day_part {
850 date_str.push('-');
851 date_str.push_str(&day_str);
852 }
853 }
854
855 date_str })
857 .boxed();
858
859 let unit_keyword = choice((
873 text::keyword("year").to("year".to_string()),
875 text::keyword("month").to("month".to_string()),
876 text::keyword("week").to("week".to_string()),
877 text::keyword("day").to("day".to_string()),
878 text::keyword("hour").to("hour".to_string()),
879 text::keyword("minute").to("minute".to_string()),
880 text::keyword("second").to("second".to_string()),
881 text::keyword("millisecond").to("millisecond".to_string()),
882 text::keyword("years").to("years".to_string()),
884 text::keyword("months").to("months".to_string()),
885 text::keyword("weeks").to("weeks".to_string()),
886 text::keyword("days").to("days".to_string()),
887 text::keyword("hours").to("hours".to_string()),
888 text::keyword("minutes").to("minutes".to_string()),
889 text::keyword("seconds").to("seconds".to_string()),
890 text::keyword("milliseconds").to("milliseconds".to_string()),
891 ));
892
893 let unit_string_literal = just('\'')
896 .ignore_then(
897 none_of("\\\'")
898 .map(|c: char| c as u32)
899 .or(esc)
900 .repeated()
901 .collect::<Vec<u32>>(),
902 )
903 .then_ignore(just('\''))
904 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)));
905
906 let unit = choice((
908 unit_keyword, unit_string_literal, ))
911 .boxed() .padded(); let integer_for_quantity = any()
916 .filter(|c: &char| c.is_ascii_digit())
917 .repeated()
918 .at_least(1)
919 .collect::<String>()
920 .try_map(|digits: String, span| match i64::from_str(&digits) {
921 Ok(n) => Ok(n), Err(_) => Err(Rich::custom(span, format!("Invalid integer: {}", digits))),
923 });
924
925 let number_for_quantity = any()
926 .filter(|c: &char| c.is_ascii_digit())
927 .repeated()
928 .at_least(1)
929 .collect::<String>()
930 .then(just('.'))
931 .then(
932 any()
933 .filter(|c: &char| c.is_ascii_digit())
934 .repeated()
935 .at_least(1)
936 .collect::<String>(),
937 )
938 .try_map(|((i, _), d), span| {
939 let num_str = format!("{}.{}", i, d);
940 match Decimal::from_str(&num_str) {
941 Ok(decimal) => Ok(decimal), Err(_) => Err(Rich::custom(span, format!("Invalid number: {}", num_str))),
943 }
944 });
945
946 let quantity = choice((
949 integer_for_quantity
951 .then_ignore(text::whitespace().at_least(1)) .then(unit.clone()) .map(|(i, u_str)| Literal::Quantity(Decimal::from(i), u_str)), number_for_quantity
956 .then_ignore(text::whitespace().at_least(1)) .then(unit.clone()) .map(|(d, u_str)| Literal::Quantity(d, u_str)), ));
960
961 let datetime_literal = just('@')
965 .ignore_then(date_format_str.clone())
966 .then_ignore(just('T'))
967 .then(time_format)
968 .then(timezone_format.clone().or_not())
969 .try_map(|((date_str, time_str), tz_opt), span| {
970 let full_str = if let Some(tz) = tz_opt {
971 format!("{}T{}{}", date_str, time_str, tz)
972 } else {
973 format!("{}T{}", date_str, time_str)
974 };
975
976 helios_fhir::PrecisionDateTime::parse(&full_str)
977 .ok_or_else(|| Rich::custom(span, format!("Invalid datetime format: {}", full_str)))
978 .map(Literal::DateTime)
979 });
980
981 let partial_datetime_literal = just('@')
983 .ignore_then(date_format_str.clone())
984 .then_ignore(just('T'))
985 .try_map(|date_str, span| {
986 let full_str = format!("{}T", date_str);
987 helios_fhir::PrecisionDateTime::parse(&full_str)
988 .ok_or_else(|| {
989 Rich::custom(
990 span,
991 format!("Invalid partial datetime format: {}", full_str),
992 )
993 })
994 .map(Literal::DateTime)
995 });
996
997 let time_literal = just('@')
1000 .ignore_then(
1001 just('T')
1002 .ignore_then(time_format)
1003 .then(timezone_format.or_not()), )
1005 .try_map(|(time_str, tz_opt), span| {
1006 if tz_opt.is_some() {
1008 Err(Rich::custom(
1009 span,
1010 "Time literal cannot have a timezone offset",
1011 ))
1012 } else {
1013 helios_fhir::PrecisionTime::parse(&time_str)
1014 .ok_or_else(|| Rich::custom(span, format!("Invalid time format: {}", time_str)))
1015 .map(Literal::Time)
1016 }
1017 });
1018
1019 let date_literal = just('@')
1021 .ignore_then(date_format_str.clone())
1022 .try_map(|date_str, span| {
1023 helios_fhir::PrecisionDate::parse(&date_str)
1024 .ok_or_else(|| Rich::custom(span, format!("Invalid date format: {}", date_str)))
1025 .map(Literal::Date)
1026 });
1027
1028 let literal = choice((
1032 null,
1033 boolean,
1034 string,
1035 quantity, number, integer, padded!(datetime_literal), padded!(partial_datetime_literal), padded!(time_literal), padded!(date_literal), ))
1043 .map(Term::Literal);
1044
1045 let standard_identifier = any()
1047 .filter(|c: &char| c.is_ascii_alphabetic() || *c == '_')
1048 .then(
1049 any()
1050 .filter(|c: &char| c.is_ascii_alphanumeric() || *c == '_')
1051 .repeated()
1052 .collect::<Vec<_>>(),
1053 )
1054 .map(|(first, rest): (char, Vec<char>)| {
1055 let mut s = first.to_string();
1056 s.extend(rest);
1057 s
1058 })
1059 .padded();
1060
1061 let delimited_identifier = just('`')
1063 .ignore_then(
1064 none_of("`")
1065 .map(|c: char| c as u32)
1066 .or(esc)
1067 .repeated()
1068 .collect::<Vec<u32>>(),
1069 )
1070 .then_ignore(just('`'))
1071 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)))
1072 .padded();
1073
1074 let identifier = choice((
1079 standard_identifier,
1080 delimited_identifier,
1081 text::keyword("as").to(String::from("as")),
1083 text::keyword("contains").to(String::from("contains")),
1084 text::keyword("in").to(String::from("in")),
1085 text::keyword("is").to(String::from("is")),
1086 text::keyword("true").to(String::from("true")), text::keyword("false").to(String::from("false")), ));
1090
1091 let qualified_identifier = {
1097 let explicit_namespace_type = identifier
1099 .clone()
1100 .then(just('.').ignore_then(identifier.clone()))
1101 .map(|(namespace, type_name)| {
1102 let clean_ns = clean_backtick_identifier(&namespace);
1104 let clean_type = clean_backtick_identifier(&type_name);
1105 TypeSpecifier::QualifiedIdentifier(clean_ns, Some(clean_type))
1106 });
1107
1108 let standalone_type = identifier.clone().map(|id| {
1110 let clean_id = clean_backtick_identifier(&id);
1111
1112 if clean_id.contains('.') {
1114 if let Some(last_dot_pos) = clean_id.rfind('.') {
1117 let namespace = clean_id[..last_dot_pos].to_string();
1118 let type_name = clean_id[last_dot_pos + 1..].to_string();
1119 TypeSpecifier::QualifiedIdentifier(namespace, Some(type_name))
1120 } else {
1121 TypeSpecifier::QualifiedIdentifier(clean_id, None)
1123 }
1124 } else {
1125 TypeSpecifier::QualifiedIdentifier(clean_id, None)
1127 }
1128 });
1129
1130 choice((explicit_namespace_type.boxed(), standalone_type.boxed())).boxed()
1132 };
1133 let qualified_identifier = padded!(qualified_identifier);
1134
1135 let string_for_external = just('\'')
1137 .ignore_then(
1138 none_of("\'\\")
1139 .map(|c: char| c as u32)
1140 .or(esc)
1141 .repeated()
1142 .collect::<Vec<u32>>(),
1143 )
1144 .then_ignore(just('\''))
1145 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)))
1146 .padded();
1147
1148 let external_constant = just('%')
1150 .ignore_then(choice((identifier.clone(), string_for_external)))
1151 .map(Term::ExternalConstant)
1152 .padded();
1153
1154 recursive(|expr| {
1157 let atom = choice((
1159 literal.clone().map(Expression::Term).boxed(), external_constant.clone().map(Expression::Term).boxed(),
1162 identifier
1164 .clone()
1165 .then(
1166 expr.clone()
1167 .separated_by(just(',').padded())
1168 .allow_trailing()
1169 .collect::<Vec<_>>()
1170 .delimited_by(just('(').padded(), just(')').padded()),
1172 )
1173 .map(|(name, params)| {
1175 Expression::Term(Term::Invocation(Invocation::Function(name, params)))
1176 })
1177 .boxed(),
1178 identifier
1180 .clone()
1181 .then(
1182 identifier
1183 .clone()
1184 .then_ignore(just(':').padded())
1185 .then(expr.clone().boxed())
1186 .separated_by(just(',').padded())
1187 .allow_trailing()
1188 .collect::<Vec<_>>()
1189 .delimited_by(just('{').padded(), just('}').padded()),
1190 )
1191 .map(|(type_name, fields)| {
1192 Expression::InstanceSelector(
1193 type_name,
1194 fields.into_iter().map(|(k, v)| (k, Box::new(v))).collect(),
1195 )
1196 })
1197 .boxed(),
1198 choice((
1200 identifier.clone().map(Invocation::Member),
1201 just("$this").to(Invocation::This),
1202 just("$index").to(Invocation::Index),
1203 just("$total").to(Invocation::Total),
1204 ))
1205 .map(Term::Invocation) .map(Expression::Term) .boxed(),
1208 expr.clone()
1210 .boxed()
1211 .delimited_by(just('(').padded(), just(')').padded())
1212 .boxed(),
1213 ))
1214 .padded();
1215
1216 let postfix_op = choice((
1218 just('.')
1220 .ignore_then(
1221 identifier.clone().then(
1222 expr.clone()
1224 .boxed()
1225 .separated_by(just(',').padded())
1226 .allow_trailing()
1227 .collect::<Vec<_>>()
1228 .delimited_by(just('(').padded(), just(')').padded())
1229 .or_not(), ),
1231 )
1232 .map(|(name, params_opt)| {
1233 let invocation = match params_opt {
1235 Some(params) => Invocation::Function(name, params),
1236 None => Invocation::Member(name),
1237 };
1238 Box::new(move |left: Expression| {
1240 Expression::Invocation(Box::new(left), invocation.clone())
1241 }) as Box<dyn Fn(Expression) -> Expression>
1242 }),
1243 expr.clone()
1245 .delimited_by(just('[').padded(), just(']').padded())
1246 .map(|idx| {
1247 Box::new(move |left: Expression| {
1248 Expression::Indexer(Box::new(left), Box::new(idx.clone()))
1249 }) as Box<dyn Fn(Expression) -> Expression>
1250 }),
1251 ))
1252 .boxed(); let atom_with_postfix = atom
1255 .clone()
1256 .then(postfix_op.repeated().collect::<Vec<_>>())
1257 .map(|(left, ops)| ops.into_iter().fold(left, |acc, op| op(acc)));
1258
1259 let prefix_op = choice((just('+').to('+'), just('-').to('-'))).padded();
1261
1262 let term_with_polarity = prefix_op
1263 .repeated()
1264 .collect::<Vec<_>>()
1265 .then(atom_with_postfix)
1266 .map(|(ops, right)| {
1267 ops.into_iter()
1268 .rev()
1269 .fold(right, |acc, op| Expression::Polarity(op, Box::new(acc)))
1270 });
1271
1272 let op_mul = choice((
1276 just('*').to("*"),
1277 just('/').to("/"),
1278 text::keyword("div").to("div"),
1279 text::keyword("mod").to("mod"),
1280 ))
1281 .padded();
1282 let multiplicative = term_with_polarity
1283 .clone()
1284 .then(
1285 op_mul
1286 .then(term_with_polarity)
1287 .repeated()
1288 .collect::<Vec<_>>(),
1289 )
1290 .map(|(left, ops)| {
1291 ops.into_iter().fold(left, |acc, (op_str, right)| {
1292 Expression::Multiplicative(Box::new(acc), op_str.to_string(), Box::new(right))
1293 })
1294 });
1295
1296 let op_add = choice((just('+').to("+"), just('-').to("-"), just('&').to("&"))).padded();
1298 let additive = multiplicative
1299 .clone()
1300 .then(op_add.then(multiplicative).repeated().collect::<Vec<_>>())
1301 .map(|(left, ops)| {
1302 ops.into_iter().fold(left, |acc, (op_str, right)| {
1303 Expression::Additive(Box::new(acc), op_str.to_string(), Box::new(right))
1304 })
1305 });
1306
1307 let op_type = choice((text::keyword("is").to("is"), text::keyword("as").to("as"))).padded();
1310 let type_expr = additive
1311 .clone()
1312 .then(
1313 op_type
1314 .then(qualified_identifier.clone())
1315 .repeated()
1316 .collect::<Vec<_>>(),
1317 ) .map(|(left, ops)| {
1319 ops.into_iter().fold(left, |acc, (op_str, type_spec)| {
1320 Expression::Type(Box::new(acc), op_str.to_string(), type_spec)
1321 })
1322 });
1323
1324 let op_union = just('|').padded();
1326 let union = type_expr
1327 .clone()
1328 .then(op_union.then(type_expr).repeated().collect::<Vec<_>>())
1329 .map(|(left, ops)| {
1330 ops.into_iter().fold(left, |acc, (_, right)| {
1331 Expression::Union(Box::new(acc), Box::new(right))
1332 })
1333 });
1334
1335 let op_ineq = choice((
1337 just("<=").to("<="),
1338 just("<").to("<"),
1339 just(">=").to(">="),
1340 just(">").to(">"),
1341 ))
1342 .padded();
1343 let inequality = union
1344 .clone()
1345 .then(op_ineq.then(union).repeated().collect::<Vec<_>>())
1346 .map(|(left, ops)| {
1347 ops.into_iter().fold(left, |acc, (op_str, right)| {
1348 Expression::Inequality(Box::new(acc), op_str.to_string(), Box::new(right))
1349 })
1350 });
1351
1352 let op_eq = choice((
1354 just("=").to("="),
1355 just("~").to("~"),
1356 just("!=").to("!="),
1357 just("!~").to("!~"),
1358 ))
1359 .padded();
1360 let equality = inequality
1361 .clone()
1362 .boxed()
1363 .then(
1364 op_eq
1365 .then(inequality.clone().boxed())
1366 .repeated()
1367 .collect::<Vec<_>>(),
1368 )
1369 .map(|(left, ops)| {
1370 ops.into_iter().fold(left, |acc, (op_str, right)| {
1371 Expression::Equality(Box::new(acc), op_str.to_string(), Box::new(right))
1372 })
1373 });
1374
1375 let op_mem = choice((
1377 text::keyword("in").to("in"),
1378 text::keyword("contains").to("contains"),
1379 ))
1380 .padded();
1381 let membership = equality
1382 .clone()
1383 .boxed()
1384 .then(
1385 op_mem
1386 .then(equality.clone().boxed())
1387 .repeated()
1388 .collect::<Vec<_>>(),
1389 )
1390 .map(|(left, ops)| {
1391 ops.into_iter().fold(left, |acc, (op_str, right)| {
1392 Expression::Membership(Box::new(acc), op_str.to_string(), Box::new(right))
1393 })
1394 });
1395
1396 let op_and = text::keyword("and").padded();
1398 let logical_and = membership
1399 .clone()
1400 .boxed()
1401 .then(
1402 op_and
1403 .then(membership.clone().boxed())
1404 .repeated()
1405 .collect::<Vec<_>>(),
1406 )
1407 .map(|(left, ops)| {
1408 ops.into_iter().fold(left, |acc, (_, right)| {
1409 Expression::And(Box::new(acc), Box::new(right))
1410 })
1411 });
1412
1413 let op_or = choice((text::keyword("or").to("or"), text::keyword("xor").to("xor"))).padded();
1415 let logical_or = logical_and
1416 .clone()
1417 .boxed()
1418 .then(
1419 op_or
1420 .then(logical_and.clone().boxed())
1421 .repeated()
1422 .collect::<Vec<_>>(),
1423 )
1424 .map(|(left, ops)| {
1425 ops.into_iter().fold(left, |acc, (op_str, right)| {
1426 Expression::Or(Box::new(acc), op_str.to_string(), Box::new(right))
1427 })
1428 });
1429
1430 let op_implies = text::keyword("implies").padded();
1432 logical_or
1433 .clone()
1434 .boxed()
1435 .then(
1436 op_implies
1437 .then(logical_or.clone().boxed())
1438 .repeated()
1439 .collect::<Vec<_>>(),
1440 )
1441 .map(|(left, ops)| {
1442 ops.into_iter().fold(left, |acc, (_, right)| {
1443 Expression::Implies(Box::new(acc), Box::new(right))
1444 })
1445 })
1446 }) .then_ignore(end()) }
1449
1450pub fn spanned_parser<'src>()
1458-> impl Parser<'src, &'src str, SpannedExpression, extra::Err<Rich<'src, char>>> + Clone + 'src {
1459 let esc = just('\\').ignore_then(choice((
1462 just('`').to('`' as u32),
1463 just('\'').to('\'' as u32),
1464 just('\\').to('\\' as u32),
1465 just('/').to('/' as u32),
1466 just('f').to(0x000C_u32),
1467 just('n').to('\n' as u32),
1468 just('r').to('\r' as u32),
1469 just('t').to('\t' as u32),
1470 just('"').to('"' as u32),
1471 just('u').ignore_then(
1472 any()
1473 .filter(|c: &char| c.is_ascii_hexdigit())
1474 .repeated()
1475 .exactly(4)
1476 .collect::<String>()
1477 .try_map(
1478 |digits: String, span| match u32::from_str_radix(&digits, 16) {
1479 Ok(code) => Ok(code),
1480 Err(_) => Err(Rich::custom(span, "Invalid hex digits")),
1481 },
1482 ),
1483 ),
1484 )));
1485
1486 let null = just('{').then(just('}')).to(Literal::Null);
1489
1490 let boolean = choice((
1491 text::keyword("true").to(Literal::Boolean(true)),
1492 text::keyword("false").to(Literal::Boolean(false)),
1493 ))
1494 .boxed();
1495
1496 let string = just('\'')
1497 .ignore_then(
1498 none_of("\\\'")
1499 .map(|c: char| c as u32)
1500 .or(esc)
1501 .repeated()
1502 .collect::<Vec<u32>>(),
1503 )
1504 .then_ignore(just('\''))
1505 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)))
1506 .map(Literal::String)
1507 .boxed();
1508
1509 let integer = any()
1510 .filter(|c: &char| c.is_ascii_digit())
1511 .repeated()
1512 .at_least(1)
1513 .collect::<String>()
1514 .try_map(|digits: String, span| match i64::from_str(&digits) {
1515 Ok(n) => Ok(Literal::Integer(n)),
1516 Err(_) => Err(Rich::custom(span, format!("Invalid integer: {}", digits))),
1517 });
1518 let integer = custom_padded(integer);
1519
1520 let number = any()
1521 .filter(|c: &char| c.is_ascii_digit())
1522 .repeated()
1523 .at_least(1)
1524 .collect::<String>()
1525 .then(just('.'))
1526 .then(
1527 any()
1528 .filter(|c: &char| c.is_ascii_digit())
1529 .repeated()
1530 .at_least(1)
1531 .collect::<String>(),
1532 )
1533 .try_map(|((i, _), d), span| {
1534 let num_str = format!("{}.{}", i, d);
1535 match Decimal::from_str(&num_str) {
1536 Ok(decimal) => Ok(Literal::Number(decimal)),
1537 Err(_) => Err(Rich::custom(span, format!("Invalid number: {}", num_str))),
1538 }
1539 })
1540 .padded();
1541
1542 let time_format = any()
1543 .filter(|c: &char| c.is_ascii_digit())
1544 .repeated()
1545 .at_least(2)
1546 .at_most(2)
1547 .collect::<String>()
1548 .then(
1549 just(':')
1550 .ignore_then(
1551 any()
1552 .filter(|c: &char| c.is_ascii_digit())
1553 .repeated()
1554 .at_least(2)
1555 .at_most(2)
1556 .collect::<String>(),
1557 )
1558 .then(
1559 just(':')
1560 .ignore_then(
1561 any()
1562 .filter(|c: &char| c.is_ascii_digit())
1563 .repeated()
1564 .at_least(2)
1565 .at_most(2)
1566 .collect::<String>(),
1567 )
1568 .then(
1569 just('.')
1570 .ignore_then(
1571 any()
1572 .filter(|c: &char| c.is_ascii_digit())
1573 .repeated()
1574 .at_least(1)
1575 .at_most(3)
1576 .collect::<String>(),
1577 )
1578 .or_not(),
1579 )
1580 .or_not(),
1581 )
1582 .or_not(),
1583 )
1584 .map(|(hours, rest_opt)| {
1585 let mut result = hours;
1586 if let Some((minutes, seconds_part)) = rest_opt {
1587 result.push(':');
1588 result.push_str(&minutes);
1589 if let Some((seconds, milliseconds)) = seconds_part {
1590 result.push(':');
1591 result.push_str(&seconds);
1592 if let Some(ms) = milliseconds {
1593 result.push('.');
1594 result.push_str(&ms);
1595 }
1596 }
1597 }
1598 result
1599 });
1600
1601 let timezone_format = just('Z').to("Z".to_string()).or(one_of("+-")
1602 .map(|c: char| c.to_string())
1603 .then(
1604 any()
1605 .filter(|c: &char| c.is_ascii_digit())
1606 .repeated()
1607 .at_most(2)
1608 .at_least(2)
1609 .collect::<String>(),
1610 )
1611 .then(just(':'))
1612 .then(
1613 any()
1614 .filter(|c: &char| c.is_ascii_digit())
1615 .repeated()
1616 .at_most(2)
1617 .at_least(2)
1618 .collect::<String>(),
1619 )
1620 .map(|(((sign, hour), _), min)| format!("{}{}:{}", sign, hour, min)));
1621
1622 let date_format_str = any()
1623 .filter(|c: &char| c.is_ascii_digit())
1624 .repeated()
1625 .exactly(4)
1626 .collect::<String>()
1627 .then(
1628 just('-')
1629 .ignore_then(
1630 any()
1631 .filter(|c: &char| c.is_ascii_digit())
1632 .repeated()
1633 .exactly(2)
1634 .collect::<String>()
1635 .then(
1636 just('-')
1637 .ignore_then(
1638 any()
1639 .filter(|c: &char| c.is_ascii_digit())
1640 .repeated()
1641 .exactly(2)
1642 .collect::<String>(),
1643 )
1644 .or_not(),
1645 ),
1646 )
1647 .or_not(),
1648 )
1649 .map(|(year, month_part)| {
1650 let mut date_str = year;
1651 if let Some((month_str, day_part)) = month_part {
1652 date_str.push('-');
1653 date_str.push_str(&month_str);
1654 if let Some(day_str) = day_part {
1655 date_str.push('-');
1656 date_str.push_str(&day_str);
1657 }
1658 }
1659 date_str
1660 })
1661 .boxed();
1662
1663 let unit_keyword = choice((
1664 text::keyword("year").to("year".to_string()),
1665 text::keyword("month").to("month".to_string()),
1666 text::keyword("week").to("week".to_string()),
1667 text::keyword("day").to("day".to_string()),
1668 text::keyword("hour").to("hour".to_string()),
1669 text::keyword("minute").to("minute".to_string()),
1670 text::keyword("second").to("second".to_string()),
1671 text::keyword("millisecond").to("millisecond".to_string()),
1672 text::keyword("years").to("years".to_string()),
1673 text::keyword("months").to("months".to_string()),
1674 text::keyword("weeks").to("weeks".to_string()),
1675 text::keyword("days").to("days".to_string()),
1676 text::keyword("hours").to("hours".to_string()),
1677 text::keyword("minutes").to("minutes".to_string()),
1678 text::keyword("seconds").to("seconds".to_string()),
1679 text::keyword("milliseconds").to("milliseconds".to_string()),
1680 ));
1681
1682 let unit_string_literal = just('\'')
1683 .ignore_then(
1684 none_of("\\\'")
1685 .map(|c: char| c as u32)
1686 .or(esc)
1687 .repeated()
1688 .collect::<Vec<u32>>(),
1689 )
1690 .then_ignore(just('\''))
1691 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)));
1692
1693 let unit = choice((unit_keyword, unit_string_literal)).boxed().padded();
1694
1695 let integer_for_quantity = any()
1696 .filter(|c: &char| c.is_ascii_digit())
1697 .repeated()
1698 .at_least(1)
1699 .collect::<String>()
1700 .try_map(|digits: String, span| match i64::from_str(&digits) {
1701 Ok(n) => Ok(n),
1702 Err(_) => Err(Rich::custom(span, format!("Invalid integer: {}", digits))),
1703 });
1704
1705 let number_for_quantity = any()
1706 .filter(|c: &char| c.is_ascii_digit())
1707 .repeated()
1708 .at_least(1)
1709 .collect::<String>()
1710 .then(just('.'))
1711 .then(
1712 any()
1713 .filter(|c: &char| c.is_ascii_digit())
1714 .repeated()
1715 .at_least(1)
1716 .collect::<String>(),
1717 )
1718 .try_map(|((i, _), d), span| {
1719 let num_str = format!("{}.{}", i, d);
1720 match Decimal::from_str(&num_str) {
1721 Ok(decimal) => Ok(decimal),
1722 Err(_) => Err(Rich::custom(span, format!("Invalid number: {}", num_str))),
1723 }
1724 });
1725
1726 let quantity = choice((
1727 integer_for_quantity
1728 .then_ignore(text::whitespace().at_least(1))
1729 .then(unit.clone())
1730 .map(|(i, u_str)| Literal::Quantity(Decimal::from(i), u_str)),
1731 number_for_quantity
1732 .then_ignore(text::whitespace().at_least(1))
1733 .then(unit.clone())
1734 .map(|(d, u_str)| Literal::Quantity(d, u_str)),
1735 ));
1736
1737 let datetime_literal = just('@')
1738 .ignore_then(date_format_str.clone())
1739 .then_ignore(just('T'))
1740 .then(time_format)
1741 .then(timezone_format.clone().or_not())
1742 .try_map(|((date_str, time_str), tz_opt), span| {
1743 let full_str = if let Some(tz) = tz_opt {
1744 format!("{}T{}{}", date_str, time_str, tz)
1745 } else {
1746 format!("{}T{}", date_str, time_str)
1747 };
1748 helios_fhir::PrecisionDateTime::parse(&full_str)
1749 .ok_or_else(|| Rich::custom(span, format!("Invalid datetime format: {}", full_str)))
1750 .map(Literal::DateTime)
1751 });
1752
1753 let partial_datetime_literal = just('@')
1754 .ignore_then(date_format_str.clone())
1755 .then_ignore(just('T'))
1756 .try_map(|date_str, span| {
1757 let full_str = format!("{}T", date_str);
1758 helios_fhir::PrecisionDateTime::parse(&full_str)
1759 .ok_or_else(|| {
1760 Rich::custom(
1761 span,
1762 format!("Invalid partial datetime format: {}", full_str),
1763 )
1764 })
1765 .map(Literal::DateTime)
1766 });
1767
1768 let time_literal = just('@')
1769 .ignore_then(
1770 just('T')
1771 .ignore_then(time_format)
1772 .then(timezone_format.or_not()),
1773 )
1774 .try_map(|(time_str, tz_opt), span| {
1775 if tz_opt.is_some() {
1776 Err(Rich::custom(
1777 span,
1778 "Time literal cannot have a timezone offset",
1779 ))
1780 } else {
1781 helios_fhir::PrecisionTime::parse(&time_str)
1782 .ok_or_else(|| Rich::custom(span, format!("Invalid time format: {}", time_str)))
1783 .map(Literal::Time)
1784 }
1785 });
1786
1787 let date_literal = just('@')
1788 .ignore_then(date_format_str.clone())
1789 .try_map(|date_str, span| {
1790 helios_fhir::PrecisionDate::parse(&date_str)
1791 .ok_or_else(|| Rich::custom(span, format!("Invalid date format: {}", date_str)))
1792 .map(Literal::Date)
1793 });
1794
1795 let literal = choice((
1796 null,
1797 boolean,
1798 string,
1799 quantity,
1800 number,
1801 integer,
1802 custom_padded(datetime_literal),
1803 custom_padded(partial_datetime_literal),
1804 custom_padded(time_literal),
1805 custom_padded(date_literal),
1806 ))
1807 .map(Term::Literal);
1808
1809 let standard_identifier = any()
1812 .filter(|c: &char| c.is_ascii_alphabetic() || *c == '_')
1813 .then(
1814 any()
1815 .filter(|c: &char| c.is_ascii_alphanumeric() || *c == '_')
1816 .repeated()
1817 .collect::<Vec<_>>(),
1818 )
1819 .map(|(first, rest): (char, Vec<char>)| {
1820 let mut s = first.to_string();
1821 s.extend(rest);
1822 s
1823 })
1824 .padded();
1825
1826 let delimited_identifier = just('`')
1827 .ignore_then(
1828 none_of("`")
1829 .map(|c: char| c as u32)
1830 .or(esc)
1831 .repeated()
1832 .collect::<Vec<u32>>(),
1833 )
1834 .then_ignore(just('`'))
1835 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)))
1836 .padded();
1837
1838 let identifier = choice((
1839 standard_identifier,
1840 delimited_identifier,
1841 text::keyword("as").to(String::from("as")),
1842 text::keyword("contains").to(String::from("contains")),
1843 text::keyword("in").to(String::from("in")),
1844 text::keyword("is").to(String::from("is")),
1845 text::keyword("true").to(String::from("true")),
1846 text::keyword("false").to(String::from("false")),
1847 ));
1848
1849 let qualified_identifier = {
1850 let explicit_namespace_type = identifier
1851 .clone()
1852 .then(just('.').ignore_then(identifier.clone()))
1853 .map(|(namespace, type_name)| {
1854 let clean_ns = clean_backtick_identifier(&namespace);
1855 let clean_type = clean_backtick_identifier(&type_name);
1856 TypeSpecifier::QualifiedIdentifier(clean_ns, Some(clean_type))
1857 });
1858
1859 let standalone_type = identifier.clone().map(|id| {
1860 let clean_id = clean_backtick_identifier(&id);
1861 if clean_id.contains('.') {
1862 if let Some(last_dot_pos) = clean_id.rfind('.') {
1863 let namespace = clean_id[..last_dot_pos].to_string();
1864 let type_name = clean_id[last_dot_pos + 1..].to_string();
1865 TypeSpecifier::QualifiedIdentifier(namespace, Some(type_name))
1866 } else {
1867 TypeSpecifier::QualifiedIdentifier(clean_id, None)
1868 }
1869 } else {
1870 TypeSpecifier::QualifiedIdentifier(clean_id, None)
1871 }
1872 });
1873
1874 choice((explicit_namespace_type.boxed(), standalone_type.boxed())).boxed()
1875 };
1876 let qualified_identifier = custom_padded(qualified_identifier);
1877
1878 let string_for_external = just('\'')
1879 .ignore_then(
1880 none_of("\'\\")
1881 .map(|c: char| c as u32)
1882 .or(esc)
1883 .repeated()
1884 .collect::<Vec<u32>>(),
1885 )
1886 .then_ignore(just('\''))
1887 .try_map(|codes, span| combine_string_code_units(codes).map_err(|e| Rich::custom(span, e)))
1888 .padded();
1889
1890 let external_constant = just('%')
1891 .ignore_then(choice((identifier.clone(), string_for_external)))
1892 .map(Term::ExternalConstant)
1893 .padded();
1894
1895 recursive(
1898 |spanned_expr: Recursive<
1899 dyn Parser<'src, &'src str, SpannedExpression, extra::Err<Rich<'src, char>>> + 'src,
1900 >| {
1901 #[inline]
1903 fn make_spanned(kind: SpannedExprKind, start: usize, end: usize) -> SpannedExpression {
1904 SpannedExpression {
1905 kind,
1906 span: ExprSpan {
1907 position: start,
1908 length: end - start,
1909 },
1910 }
1911 }
1912
1913 let atom = choice((
1915 literal
1917 .clone()
1918 .map_with(|term, extra| {
1919 let s = extra.span();
1920 let spanned_term = match term {
1921 Term::Literal(l) => SpannedTerm::Literal(l),
1922 _ => unreachable!(),
1923 };
1924 make_spanned(SpannedExprKind::Term(spanned_term), s.start, s.end)
1925 })
1926 .boxed(),
1927 external_constant
1929 .clone()
1930 .map_with(|term, extra| {
1931 let s = extra.span();
1932 let spanned_term = match term {
1933 Term::ExternalConstant(name) => SpannedTerm::ExternalConstant(name),
1934 _ => unreachable!(),
1935 };
1936 make_spanned(SpannedExprKind::Term(spanned_term), s.start, s.end)
1937 })
1938 .boxed(),
1939 identifier
1941 .clone()
1942 .then(
1943 spanned_expr
1944 .clone()
1945 .separated_by(just(',').padded())
1946 .allow_trailing()
1947 .collect::<Vec<_>>()
1948 .delimited_by(just('(').padded(), just(')').padded()),
1949 )
1950 .map_with(|(name, params), extra| {
1951 let s = extra.span();
1952 make_spanned(
1953 SpannedExprKind::Term(SpannedTerm::Invocation(
1954 SpannedInvocation::Function(name, params),
1955 )),
1956 s.start,
1957 s.end,
1958 )
1959 })
1960 .boxed(),
1961 identifier
1963 .clone()
1964 .then(
1965 identifier
1966 .clone()
1967 .then_ignore(just(':').padded())
1968 .then(spanned_expr.clone().boxed())
1969 .separated_by(just(',').padded())
1970 .allow_trailing()
1971 .collect::<Vec<_>>()
1972 .delimited_by(just('{').padded(), just('}').padded()),
1973 )
1974 .map_with(|(type_name, fields), extra| {
1975 let s = extra.span();
1976 make_spanned(
1977 SpannedExprKind::InstanceSelector(
1978 type_name,
1979 fields.into_iter().map(|(k, v)| (k, Box::new(v))).collect(),
1980 ),
1981 s.start,
1982 s.end,
1983 )
1984 })
1985 .boxed(),
1986 choice((
1988 identifier.clone().map(SpannedInvocation::Member),
1989 just("$this").to(SpannedInvocation::This),
1990 just("$index").to(SpannedInvocation::Index),
1991 just("$total").to(SpannedInvocation::Total),
1992 ))
1993 .map_with(|inv, extra| {
1994 let s = extra.span();
1995 make_spanned(
1996 SpannedExprKind::Term(SpannedTerm::Invocation(inv)),
1997 s.start,
1998 s.end,
1999 )
2000 })
2001 .boxed(),
2002 spanned_expr
2004 .clone()
2005 .boxed()
2006 .delimited_by(just('(').padded(), just(')').padded())
2007 .map_with(|inner, extra| {
2008 let s = extra.span();
2009 make_spanned(
2010 SpannedExprKind::Term(SpannedTerm::Parenthesized(Box::new(inner))),
2011 s.start,
2012 s.end,
2013 )
2014 })
2015 .boxed(),
2016 ))
2017 .padded();
2018
2019 let postfix_op = choice((
2021 just('.')
2023 .ignore_then(
2024 identifier.clone().then(
2025 spanned_expr
2026 .clone()
2027 .boxed()
2028 .separated_by(just(',').padded())
2029 .allow_trailing()
2030 .collect::<Vec<_>>()
2031 .delimited_by(just('(').padded(), just(')').padded())
2032 .or_not(),
2033 ),
2034 )
2035 .map_with(|(name, params_opt), extra| {
2036 let op_end = extra.span().end;
2037 let invocation = match params_opt {
2038 Some(params) => SpannedInvocation::Function(name, params),
2039 None => SpannedInvocation::Member(name),
2040 };
2041 Box::new(move |left: SpannedExpression| {
2042 let start = left.span.position;
2043 make_spanned(
2044 SpannedExprKind::Invocation(Box::new(left), invocation.clone()),
2045 start,
2046 op_end,
2047 )
2048 })
2049 as Box<dyn Fn(SpannedExpression) -> SpannedExpression>
2050 }),
2051 spanned_expr
2053 .clone()
2054 .delimited_by(just('[').padded(), just(']').padded())
2055 .map_with(|idx, extra| {
2056 let op_end = extra.span().end;
2057 Box::new(move |left: SpannedExpression| {
2058 let start = left.span.position;
2059 make_spanned(
2060 SpannedExprKind::Indexer(Box::new(left), Box::new(idx.clone())),
2061 start,
2062 op_end,
2063 )
2064 })
2065 as Box<dyn Fn(SpannedExpression) -> SpannedExpression>
2066 }),
2067 ))
2068 .boxed();
2069
2070 let atom_with_postfix = atom
2071 .clone()
2072 .then(postfix_op.repeated().collect::<Vec<_>>())
2073 .map(|(left, ops)| ops.into_iter().fold(left, |acc, op| op(acc)));
2074
2075 let prefix_op = choice((just('+').to('+'), just('-').to('-'))).padded();
2077
2078 let term_with_polarity = prefix_op
2079 .repeated()
2080 .collect::<Vec<_>>()
2081 .then(atom_with_postfix)
2082 .map_with(|(ops, right), extra| {
2083 if ops.is_empty() {
2084 right
2085 } else {
2086 let full_start = extra.span().start;
2087 ops.into_iter().rev().fold(right, |acc, op| {
2088 let end = acc.span.position + acc.span.length;
2089 make_spanned(
2090 SpannedExprKind::Polarity(op, Box::new(acc)),
2091 full_start,
2092 end,
2093 )
2094 })
2095 }
2096 });
2097
2098 let op_mul = choice((
2102 just('*').to("*"),
2103 just('/').to("/"),
2104 text::keyword("div").to("div"),
2105 text::keyword("mod").to("mod"),
2106 ))
2107 .padded();
2108 let multiplicative = term_with_polarity
2109 .clone()
2110 .then(
2111 op_mul
2112 .then(term_with_polarity)
2113 .repeated()
2114 .collect::<Vec<_>>(),
2115 )
2116 .map(|(left, ops)| {
2117 ops.into_iter().fold(left, |acc, (op_str, right)| {
2118 let start = acc.span.position;
2119 let end = right.span.position + right.span.length;
2120 make_spanned(
2121 SpannedExprKind::Multiplicative(
2122 Box::new(acc),
2123 op_str.to_string(),
2124 Box::new(right),
2125 ),
2126 start,
2127 end,
2128 )
2129 })
2130 });
2131
2132 let op_add = choice((just('+').to("+"), just('-').to("-"), just('&').to("&"))).padded();
2134 let additive = multiplicative
2135 .clone()
2136 .then(op_add.then(multiplicative).repeated().collect::<Vec<_>>())
2137 .map(|(left, ops)| {
2138 ops.into_iter().fold(left, |acc, (op_str, right)| {
2139 let start = acc.span.position;
2140 let end = right.span.position + right.span.length;
2141 make_spanned(
2142 SpannedExprKind::Additive(
2143 Box::new(acc),
2144 op_str.to_string(),
2145 Box::new(right),
2146 ),
2147 start,
2148 end,
2149 )
2150 })
2151 });
2152
2153 let op_type =
2155 choice((text::keyword("is").to("is"), text::keyword("as").to("as"))).padded();
2156 let type_expr = additive
2157 .clone()
2158 .then(
2159 op_type
2160 .then(qualified_identifier.clone())
2161 .repeated()
2162 .collect::<Vec<_>>(),
2163 )
2164 .map_with(|(left, ops), extra| {
2165 if ops.is_empty() {
2166 left
2167 } else {
2168 let full_end = extra.span().end;
2169 ops.into_iter().fold(left, |acc, (op_str, type_spec)| {
2170 let start = acc.span.position;
2171 make_spanned(
2172 SpannedExprKind::Type(Box::new(acc), op_str.to_string(), type_spec),
2173 start,
2174 full_end,
2175 )
2176 })
2177 }
2178 });
2179
2180 let op_union = just('|').padded();
2182 let union = type_expr
2183 .clone()
2184 .then(op_union.then(type_expr).repeated().collect::<Vec<_>>())
2185 .map(|(left, ops)| {
2186 ops.into_iter().fold(left, |acc, (_, right)| {
2187 let start = acc.span.position;
2188 let end = right.span.position + right.span.length;
2189 make_spanned(
2190 SpannedExprKind::Union(Box::new(acc), Box::new(right)),
2191 start,
2192 end,
2193 )
2194 })
2195 });
2196
2197 let op_ineq = choice((
2199 just("<=").to("<="),
2200 just("<").to("<"),
2201 just(">=").to(">="),
2202 just(">").to(">"),
2203 ))
2204 .padded();
2205 let inequality = union
2206 .clone()
2207 .then(op_ineq.then(union).repeated().collect::<Vec<_>>())
2208 .map(|(left, ops)| {
2209 ops.into_iter().fold(left, |acc, (op_str, right)| {
2210 let start = acc.span.position;
2211 let end = right.span.position + right.span.length;
2212 make_spanned(
2213 SpannedExprKind::Inequality(
2214 Box::new(acc),
2215 op_str.to_string(),
2216 Box::new(right),
2217 ),
2218 start,
2219 end,
2220 )
2221 })
2222 });
2223
2224 let op_eq = choice((
2226 just("=").to("="),
2227 just("~").to("~"),
2228 just("!=").to("!="),
2229 just("!~").to("!~"),
2230 ))
2231 .padded();
2232 let equality = inequality
2233 .clone()
2234 .boxed()
2235 .then(
2236 op_eq
2237 .then(inequality.clone().boxed())
2238 .repeated()
2239 .collect::<Vec<_>>(),
2240 )
2241 .map(|(left, ops)| {
2242 ops.into_iter().fold(left, |acc, (op_str, right)| {
2243 let start = acc.span.position;
2244 let end = right.span.position + right.span.length;
2245 make_spanned(
2246 SpannedExprKind::Equality(
2247 Box::new(acc),
2248 op_str.to_string(),
2249 Box::new(right),
2250 ),
2251 start,
2252 end,
2253 )
2254 })
2255 });
2256
2257 let op_mem = choice((
2259 text::keyword("in").to("in"),
2260 text::keyword("contains").to("contains"),
2261 ))
2262 .padded();
2263 let membership = equality
2264 .clone()
2265 .boxed()
2266 .then(
2267 op_mem
2268 .then(equality.clone().boxed())
2269 .repeated()
2270 .collect::<Vec<_>>(),
2271 )
2272 .map(|(left, ops)| {
2273 ops.into_iter().fold(left, |acc, (op_str, right)| {
2274 let start = acc.span.position;
2275 let end = right.span.position + right.span.length;
2276 make_spanned(
2277 SpannedExprKind::Membership(
2278 Box::new(acc),
2279 op_str.to_string(),
2280 Box::new(right),
2281 ),
2282 start,
2283 end,
2284 )
2285 })
2286 });
2287
2288 let op_and = text::keyword("and").padded();
2290 let logical_and = membership
2291 .clone()
2292 .boxed()
2293 .then(
2294 op_and
2295 .then(membership.clone().boxed())
2296 .repeated()
2297 .collect::<Vec<_>>(),
2298 )
2299 .map(|(left, ops)| {
2300 ops.into_iter().fold(left, |acc, (_, right)| {
2301 let start = acc.span.position;
2302 let end = right.span.position + right.span.length;
2303 make_spanned(
2304 SpannedExprKind::And(Box::new(acc), Box::new(right)),
2305 start,
2306 end,
2307 )
2308 })
2309 });
2310
2311 let op_or =
2313 choice((text::keyword("or").to("or"), text::keyword("xor").to("xor"))).padded();
2314 let logical_or = logical_and
2315 .clone()
2316 .boxed()
2317 .then(
2318 op_or
2319 .then(logical_and.clone().boxed())
2320 .repeated()
2321 .collect::<Vec<_>>(),
2322 )
2323 .map(|(left, ops)| {
2324 ops.into_iter().fold(left, |acc, (op_str, right)| {
2325 let start = acc.span.position;
2326 let end = right.span.position + right.span.length;
2327 make_spanned(
2328 SpannedExprKind::Or(Box::new(acc), op_str.to_string(), Box::new(right)),
2329 start,
2330 end,
2331 )
2332 })
2333 });
2334
2335 let op_implies = text::keyword("implies").padded();
2337 logical_or
2338 .clone()
2339 .boxed()
2340 .then(
2341 op_implies
2342 .then(logical_or.clone().boxed())
2343 .repeated()
2344 .collect::<Vec<_>>(),
2345 )
2346 .map(|(left, ops)| {
2347 ops.into_iter().fold(left, |acc, (_, right)| {
2348 let start = acc.span.position;
2349 let end = right.span.position + right.span.length;
2350 make_spanned(
2351 SpannedExprKind::Implies(Box::new(acc), Box::new(right)),
2352 start,
2353 end,
2354 )
2355 })
2356 })
2357 },
2358 )
2359 .then_ignore(end())
2360}