1use nom::{
2 branch::alt,
3 bytes::complete::tag,
4 character::complete::{none_of, one_of},
5 combinator::{cut, map, opt},
6 multi::{count, many0, many1, many_m_n},
7 sequence::{delimited, pair, preceded, terminated},
8 IResult, Parser,
9};
10use std::fmt;
11
12use super::{ws0, ParseResult, SyntaxError, SyntaxErrorKind};
13
14#[derive(Debug, PartialEq, Clone)]
15pub enum Expression {
16 Number(String),
17 BigInt(String),
18 String(StringLiteral),
19 UnaryOperation {
20 operator: UnaryOperator,
21 operand: Box<Expression>,
22 },
23 BinaryOperation {
24 operator: BinaryOperator,
25 left: Box<Expression>,
26 right: Box<Expression>,
27 },
28}
29
30impl fmt::Display for Expression {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 match self {
33 Self::Number(number) => write!(f, "{}", number),
34 Self::BigInt(bigint) => write!(f, "{}n", bigint),
35 Self::String(string) => write!(f, "\"{}\"", string.value),
36 Self::UnaryOperation { operator, operand } => match operator {
37 UnaryOperator::Try => write!(f, "({}?)", operand),
38 _ => write!(f, "({}{})", operator, operand),
39 },
40 Self::BinaryOperation {
41 operator,
42 left,
43 right,
44 } => write!(f, "({} {} {})", left, operator, right),
45 }
46 }
47}
48
49#[derive(Debug, PartialEq, Clone)]
54pub struct StringLiteral {
55 pub value: String,
57 pub interpolations: Vec<(usize, Box<Expression>)>,
59}
60
61#[derive(Debug, PartialEq, Clone)]
62enum StringPart {
63 Literal(String),
64 Interpolation(Box<Expression>),
65}
66
67#[derive(Debug, Eq, PartialEq, Clone, Copy)]
68pub enum UnaryOperator {
69 Negate,
70 LogicalNot,
71 BitwiseNot,
72 UnaryPlus,
73 UnaryMinus,
74 Try,
75}
76
77impl fmt::Display for UnaryOperator {
78 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79 match self {
80 Self::Negate => write!(f, "!"),
81 Self::LogicalNot => write!(f, "!"),
82 Self::BitwiseNot => write!(f, "~"),
83 Self::UnaryPlus => write!(f, "+"),
84 Self::UnaryMinus => write!(f, "-"),
85 Self::Try => write!(f, "?"),
86 }
87 }
88}
89
90impl std::str::FromStr for UnaryOperator {
91 type Err = ();
92
93 fn from_str(s: &str) -> Result<Self, Self::Err> {
94 match s {
95 "!" => Ok(Self::Negate),
96 "~" => Ok(Self::BitwiseNot),
97 "+" => Ok(Self::UnaryPlus),
98 "-" => Ok(Self::UnaryMinus),
99 "?" => Ok(Self::Try),
100 _ => Err(()),
101 }
102 }
103}
104
105#[derive(Debug, Eq, PartialEq, Clone, Copy)]
106pub enum Associativity {
107 LeftToRight,
108 RightToLeft,
109}
110
111#[derive(Debug, Eq, PartialEq, Clone, Copy)]
112pub enum BinaryOperator {
113 Exponent,
115 Multiply,
117 Divide,
119 Modulo,
121 Add,
123 Subtract,
125 LeftShift,
127 RightShift,
129 LessThan,
131 LessThanOrEqual,
133 GreaterThan,
135 GreaterThanOrEqual,
137 Equal,
139 NotEqual,
141 BitwiseAnd,
143 BitwiseXor,
145 BitwiseOr,
147 LogicalAnd,
149 LogicalOr,
151 Pipe,
153}
154
155impl BinaryOperator {
156 pub fn precedence(&self) -> u8 {
157 match self {
158 Self::Exponent => 13,
159 Self::Multiply | Self::Divide | Self::Modulo => 12,
160 Self::Add | Self::Subtract => 11,
161 Self::LeftShift | Self::RightShift => 10,
162 Self::LessThan
163 | Self::LessThanOrEqual
164 | Self::GreaterThan
165 | Self::GreaterThanOrEqual => 9,
166 Self::Equal | Self::NotEqual => 8,
167 Self::BitwiseAnd => 7,
168 Self::BitwiseXor => 6,
169 Self::BitwiseOr => 5,
170 Self::LogicalAnd => 4,
171 Self::LogicalOr => 3,
172 Self::Pipe => 2,
173 }
174 }
175
176 pub fn associativity(&self) -> Associativity {
177 match self {
178 Self::Exponent => Associativity::RightToLeft,
179 Self::Multiply
180 | Self::Divide
181 | Self::Modulo
182 | Self::Add
183 | Self::Subtract
184 | Self::LeftShift
185 | Self::RightShift
186 | Self::LessThan
187 | Self::LessThanOrEqual
188 | Self::GreaterThan
189 | Self::GreaterThanOrEqual
190 | Self::Equal
191 | Self::NotEqual
192 | Self::BitwiseAnd
193 | Self::BitwiseXor
194 | Self::BitwiseOr
195 | Self::LogicalAnd
196 | Self::LogicalOr
197 | Self::Pipe => Associativity::LeftToRight,
198 }
199 }
200}
201
202impl std::str::FromStr for BinaryOperator {
203 type Err = ();
204
205 fn from_str(s: &str) -> Result<Self, Self::Err> {
206 match s {
207 "**" => Ok(Self::Exponent),
208 "*" => Ok(Self::Multiply),
209 "/" => Ok(Self::Divide),
210 "%" => Ok(Self::Modulo),
211 "+" => Ok(Self::Add),
212 "-" => Ok(Self::Subtract),
213 "<<" => Ok(Self::LeftShift),
214 ">>" => Ok(Self::RightShift),
215 "<" => Ok(Self::LessThan),
216 "<=" => Ok(Self::LessThanOrEqual),
217 ">" => Ok(Self::GreaterThan),
218 ">=" => Ok(Self::GreaterThanOrEqual),
219 "==" => Ok(Self::Equal),
220 "!=" => Ok(Self::NotEqual),
221 "&" => Ok(Self::BitwiseAnd),
222 "^" => Ok(Self::BitwiseXor),
223 "|" => Ok(Self::BitwiseOr),
224 "&&" => Ok(Self::LogicalAnd),
225 "||" => Ok(Self::LogicalOr),
226 "|>" => Ok(Self::Pipe),
227 _ => Err(()),
228 }
229 }
230}
231
232impl fmt::Display for BinaryOperator {
233 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234 match self {
235 Self::Exponent => write!(f, "**"),
236 Self::Multiply => write!(f, "*"),
237 Self::Divide => write!(f, "/"),
238 Self::Modulo => write!(f, "%"),
239 Self::Add => write!(f, "+"),
240 Self::Subtract => write!(f, "-"),
241 Self::LeftShift => write!(f, "<<"),
242 Self::RightShift => write!(f, ">>"),
243 Self::LessThan => write!(f, "<"),
244 Self::LessThanOrEqual => write!(f, "<="),
245 Self::GreaterThan => write!(f, ">"),
246 Self::GreaterThanOrEqual => write!(f, ">="),
247 Self::Equal => write!(f, "=="),
248 Self::NotEqual => write!(f, "!="),
249 Self::BitwiseAnd => write!(f, "&"),
250 Self::BitwiseXor => write!(f, "^"),
251 Self::BitwiseOr => write!(f, "|"),
252 Self::LogicalAnd => write!(f, "&&"),
253 Self::LogicalOr => write!(f, "||"),
254 Self::Pipe => write!(f, "|>"),
255 }
256 }
257}
258
259fn non_zero_digit(input: &str) -> ParseResult<char> {
260 one_of("123456789")(input)
261}
262
263fn digit(input: &str) -> ParseResult<char> {
264 one_of("0123456789")(input)
265}
266
267fn hex_digit(input: &str) -> ParseResult<char> {
268 let result: IResult<&str, char> = one_of("0123456789abcdefABCDEF").parse(input);
269 match result {
270 Ok((input, c)) => Ok((input, c)),
271 Err(_) => Err(nom::Err::Error(SyntaxError {
272 input,
273 error: SyntaxErrorKind::InvalidHexDigit,
274 })),
275 }
276}
277
278fn delimited_digit(input: &str) -> ParseResult<char> {
279 if input.starts_with("__") {
280 return Err(nom::Err::Failure(SyntaxError {
281 input,
282 error: SyntaxErrorKind::ConsecutiveUnderscoreInNumericLiteral,
283 }));
284 }
285 alt((digit, preceded(tag("_"), digit))).parse(input)
286}
287
288fn whole_number(input: &str) -> ParseResult<String> {
289 if input.starts_with('_') {
290 return Err(nom::Err::Failure(SyntaxError {
291 input,
292 error: SyntaxErrorKind::NumericLiteralStartsWithUnderscore,
293 }));
294 }
295 let (input, start) = non_zero_digit(input)?;
297 let (input, digits) = many0(delimited_digit).parse(input)?;
300 let number = std::iter::once(start).chain(digits).collect::<String>();
302 Ok((input, number))
303}
304
305fn decimal_number(input: &str) -> ParseResult<String> {
306 let (input, mut number) = whole_number(input)?;
307 let (input, decimal) = opt(preceded(tag("."), many1(delimited_digit))).parse(input)?;
309 if input.starts_with('_') {
310 return Err(nom::Err::Failure(SyntaxError {
311 input,
312 error: SyntaxErrorKind::NumericLiteralEndsWithUnderscore,
313 }));
314 }
315 if let Some(decimal) = decimal {
317 number.extend(std::iter::once('.').chain(decimal));
318 }
319 Ok((input, number))
320}
321
322fn scientific_notation(input: &str) -> ParseResult<String> {
323 let (input, mut number) = decimal_number(input)?;
324 let (input, sign) = preceded(alt((tag("e"), tag("E"))), opt(one_of("+-"))).parse(input)?;
325 let (input, exponent) = many1(delimited_digit).parse(input)?;
326 if input.starts_with('_') {
327 return Err(nom::Err::Failure(SyntaxError {
328 input,
329 error: SyntaxErrorKind::NumericLiteralEndsWithUnderscore,
330 }));
331 }
332 match sign {
333 Some('-') => number.push_str("e-"),
334 Some('+') => number.push('e'),
335 None => number.push('e'),
336 _ => unreachable!(),
337 };
338 number.extend(exponent);
339
340 Ok((input, number))
341}
342
343fn parse_number(input: &str) -> ParseResult<Expression> {
344 map(alt((scientific_notation, decimal_number)), |number| {
345 Expression::Number(number)
346 })
347 .parse(input)
348}
349
350fn parse_bigint(input: &str) -> ParseResult<Expression> {
351 if input.starts_with('n') {
352 return Err(nom::Err::Failure(SyntaxError {
353 input,
354 error: SyntaxErrorKind::EmptyBigIntLiteral,
355 }));
356 }
357 map(
358 terminated(alt((scientific_notation, whole_number)), tag("n")),
359 Expression::BigInt,
360 )
361 .parse(input)
362}
363
364fn parse_escaped_char(input: &str) -> ParseResult<char> {
365 let (input, result) = alt((
366 tag("\\\\"), tag("\\\""), tag("\\n"), tag("\\r"), tag("\\t"), tag("\\0"), tag("{{"), tag("}}"), ))
375 .parse(input)?;
376 match result {
377 "\\\\" => Ok((input, '\\')),
378 "\\\"" => Ok((input, '"')),
379 "\\n" => Ok((input, '\n')),
380 "\\r" => Ok((input, '\r')),
381 "\\t" => Ok((input, '\t')),
382 "\\0" => Ok((input, '\0')),
383 "{{" => Ok((input, '{')),
384 "}}" => Ok((input, '}')),
385 _ => unreachable!(),
386 }
387}
388
389fn parse_escaped_code_point(input: &str) -> ParseResult<char> {
401 let (input, value) = alt((
402 preceded(
403 tag("\\u"),
404 cut(delimited(tag("{"), many_m_n(2, 6, hex_digit), tag("}"))),
405 ),
406 preceded(tag("\\x"), cut(count(hex_digit, 2))),
407 ))
408 .parse(input)?;
409 let value = value.iter().collect::<String>();
410 let code_point = u32::from_str_radix(&value, 16).unwrap();
411 match std::char::from_u32(code_point) {
412 Some(c) => Ok((input, c)),
413 None => Err(nom::Err::Failure(SyntaxError {
414 input,
415 error: SyntaxErrorKind::InvalidUnicodeCodePoint(code_point),
416 })),
417 }
418}
419
420fn parse_regular_char(input: &str) -> ParseResult<char> {
421 none_of("\\\"{}").parse(input)
422}
423
424fn parse_interpolation(input: &str) -> ParseResult<StringPart> {
425 map(
426 delimited(tag("{"), alt((parse_number, parse_bigint)), tag("}")),
427 |inter| StringPart::Interpolation(inter.into()),
428 )
429 .parse(input)
430}
431
432fn parse_string(input: &str) -> ParseResult<Expression> {
433 let (input, parsed) = delimited(
434 tag("\""),
435 many0(alt((
436 map(
437 many1(alt((
438 parse_regular_char,
439 parse_escaped_char,
440 parse_escaped_code_point,
441 ))),
442 |f| StringPart::Literal(f.iter().collect()),
443 ),
444 parse_interpolation,
445 ))),
446 tag("\""),
447 )
448 .parse(input)?;
449 let mut string = StringLiteral {
450 value: String::new(),
451 interpolations: vec![],
452 };
453 for part in parsed {
454 match part {
455 StringPart::Literal(literal) => string.value.push_str(&literal),
456 StringPart::Interpolation(interpolation) => {
457 string
458 .interpolations
459 .push((string.value.len(), interpolation));
460 }
461 }
462 }
463 Ok((input, Expression::String(string)))
464}
465
466fn parse_binary_operator(input: &str) -> ParseResult<BinaryOperator> {
467 map(
468 ws0(alt((
469 tag("|>"),
470 tag("**"),
471 tag("*"),
472 tag("/"),
473 tag("%"),
474 tag("+"),
475 tag("-"),
476 tag("<<"),
477 tag(">>"),
478 tag("<="),
479 tag("<"),
480 tag(">="),
481 tag(">"),
482 tag("=="),
483 tag("!="),
484 tag("&&"),
485 tag("||"),
486 tag("&"),
487 tag("^"),
488 tag("|"),
489 ))),
490 |op| op.parse().unwrap(),
491 )
492 .parse(input)
493}
494
495fn parse_unary_operator(input: &str) -> ParseResult<UnaryOperator> {
496 map(ws0(alt((tag("!"), tag("~"), tag("+"), tag("-")))), |op| {
497 op.parse().unwrap()
498 })
499 .parse(input)
500}
501
502fn parse_term(input: &str) -> ParseResult<Expression> {
503 map(
504 (
505 opt(parse_unary_operator),
506 alt((parse_string, parse_bigint, parse_number)),
507 opt(tag("?")),
508 ),
509 |(prefix, expr, postfix)| {
510 let mut expression = expr;
511 if postfix.is_some() {
512 expression = Expression::UnaryOperation {
513 operator: UnaryOperator::Try,
514 operand: Box::new(expression),
515 };
516 }
517 if let Some(op) = prefix {
518 expression = Expression::UnaryOperation {
519 operator: op,
520 operand: Box::new(expression),
521 };
522 }
523 expression
524 },
525 )
526 .parse(input)
527}
528
529pub(super) fn parse_expression(input: &str) -> ParseResult<Expression> {
549 let (input, left) = parse_term(input)?;
550 let mut output: Vec<Expression> = vec![left];
551 let mut operators = Vec::<BinaryOperator>::new();
552 let mut remaining = input;
553 loop {
554 let (input, opt_right) =
555 opt(pair(ws0(parse_binary_operator), ws0(parse_term))).parse(remaining)?;
556 remaining = input;
557 let (op, right) = match opt_right {
558 Some((op, right)) => (op, right),
560 None => break,
562 };
563 while let Some(&top) = operators.last() {
564 if top.precedence() > op.precedence()
569 || (top.precedence() == op.precedence()
570 && op.associativity() == Associativity::LeftToRight)
571 {
572 let right = output.pop().unwrap();
573 let left = output.pop().unwrap();
574 output.push(Expression::BinaryOperation {
575 operator: operators.pop().unwrap(),
576 left: Box::new(left),
577 right: Box::new(right),
578 });
579 } else {
580 break;
581 }
582 }
583 output.push(right);
584 operators.push(op);
585 }
586 while let Some(op) = operators.pop() {
587 let right = output.pop().unwrap();
588 let left = output.pop().unwrap();
589 output.push(Expression::BinaryOperation {
590 operator: op,
591 left: Box::new(left),
592 right: Box::new(right),
593 });
594 }
595 Ok((remaining, output.pop().unwrap()))
596}
597
598#[cfg(test)]
599mod tests {
600 use super::*;
601
602 macro_rules! test_expression {
603 ($name:ident, $input:expr, $expected:expr) => {
604 #[test]
605 fn $name() {
606 let (rest, result) = parse_expression($input).unwrap();
607 assert_eq!(rest, "");
608 assert_eq!(result, $expected);
609 }
610 };
611 }
612
613 macro_rules! test_error_kind {
614 ($name:ident, $input:expr, $kind:pat) => {
615 #[test]
616 fn $name() {
617 let result = parse_expression($input);
618 assert!(result.is_err());
619 let err = result.unwrap_err();
620 match err {
621 nom::Err::Failure(SyntaxError { error, .. }) => assert!(matches!(error, $kind)),
622 _ => panic!("Unexpected error: {:?}", err),
623 }
624 }
625 };
626 }
627
628 test_expression!(number_simple, "42", Expression::Number("42".into()));
629 test_expression!(number_pi, "3.14159", Expression::Number("3.14159".into()));
630 test_expression!(
631 number_pi_underscore,
632 "3.141_59",
633 Expression::Number("3.14159".into())
634 );
635 test_expression!(
636 number_billion,
637 "1000000000",
638 Expression::Number("1000000000".into())
639 );
640 test_expression!(
641 number_billion_with_underline,
642 "1_000_000_000",
643 Expression::Number("1000000000".into())
644 );
645 test_error_kind!(number_empty, "", SyntaxErrorKind::EmptyInput);
646 test_error_kind!(
647 number_underscore_at_start,
648 "_42",
649 SyntaxErrorKind::NumericLiteralStartsWithUnderscore
650 );
651 test_error_kind!(
652 number_underscore_at_end,
653 "42_",
654 SyntaxErrorKind::NumericLiteralEndsWithUnderscore
655 );
656 test_error_kind!(
657 number_decimal_underscore_at_end,
658 "42.0_",
659 SyntaxErrorKind::NumericLiteralEndsWithUnderscore
660 );
661 test_error_kind!(
662 number_exponent_underscore_at_end,
663 "42e10_",
664 SyntaxErrorKind::NumericLiteralEndsWithUnderscore
665 );
666 test_error_kind!(
667 number_consecutive_underscores,
668 "1__000",
669 SyntaxErrorKind::ConsecutiveUnderscoreInNumericLiteral
670 );
671 test_expression!(
672 number_scientific_notation,
673 "1e6",
674 Expression::Number("1e6".into())
675 );
676 test_expression!(
677 number_scientific_notation_uppercase,
678 "1E6",
679 Expression::Number("1e6".into())
680 );
681 test_expression!(
682 number_scientific_notation_positive,
683 "1e+6",
684 Expression::Number("1e6".into())
685 );
686 test_expression!(
687 number_scientific_notation_negative,
688 "1e-6",
689 Expression::Number("1e-6".into())
690 );
691 test_expression!(
692 number_scientific_notation_decimal,
693 "1.23e4",
694 Expression::Number("1.23e4".into())
695 );
696 test_expression!(
697 number_scientific_notation_decimal_positive,
698 "1.23e+4",
699 Expression::Number("1.23e4".into())
700 );
701 test_expression!(
702 number_scientific_notation_decimal_negative,
703 "1.23e-4",
704 Expression::Number("1.23e-4".into())
705 );
706
707 test_expression!(bigint_simple, "42n", Expression::BigInt("42".into()));
708 test_expression!(
709 bigint_billion,
710 "1000000000n",
711 Expression::BigInt("1000000000".into())
712 );
713 test_expression!(
714 bigint_billion_with_underline,
715 "1_000_000_000n",
716 Expression::BigInt("1000000000".into())
717 );
718 test_expression!(
719 bigint_scientific_notation,
720 "1e6n",
721 Expression::BigInt("1e6".into())
722 );
723 test_expression!(
724 bigint_scientific_notation_uppercase,
725 "1E6n",
726 Expression::BigInt("1e6".into())
727 );
728 test_expression!(
729 bigint_scientific_notation_positive,
730 "1e+6n",
731 Expression::BigInt("1e6".into())
732 );
733 test_expression!(
734 bigint_scientific_notation_negative,
735 "100e-2n",
736 Expression::BigInt("100e-2".into())
737 );
738 test_expression!(
739 bigint_scientific_notation_decimal,
740 "1.23e4n",
741 Expression::BigInt("1.23e4".into())
742 );
743 test_error_kind!(bigint_empty, "n", SyntaxErrorKind::EmptyBigIntLiteral);
744 test_error_kind!(
745 bigint_underscore_at_start,
746 "_42n",
747 SyntaxErrorKind::NumericLiteralStartsWithUnderscore
748 );
749 test_error_kind!(
750 bigint_underscore_at_end,
751 "42_n",
752 SyntaxErrorKind::NumericLiteralEndsWithUnderscore
753 );
754 test_error_kind!(
755 bigint_consecutive_underscores,
756 "1__000n",
757 SyntaxErrorKind::ConsecutiveUnderscoreInNumericLiteral
758 );
759
760 test_expression!(
761 string_empty,
762 r#""""#,
763 Expression::String(StringLiteral {
764 value: "".into(),
765 interpolations: vec![]
766 })
767 );
768 test_expression!(
769 string_simple,
770 r#""Hello, World!""#,
771 Expression::String(StringLiteral {
772 value: "Hello, World!".into(),
773 interpolations: vec![]
774 })
775 );
776 test_expression!(
777 string_escaped_chars,
778 r#""\\\"\n\r\t{{}}""#,
779 Expression::String(StringLiteral {
780 value: "\\\"\n\r\t{}".into(),
781 interpolations: vec![]
782 })
783 );
784 test_expression!(
785 string_unicode_code,
786 r#""\x41\u{41}\u{0041}\u{000041}""#,
787 Expression::String(StringLiteral {
788 value: "AAAA".into(),
789 interpolations: vec![]
790 })
791 );
792 test_expression!(
793 string_unicode_code_emoji,
794 r#""\u{2603}\u{1F600}""#,
795 Expression::String(StringLiteral {
796 value: "☃😀".into(),
797 interpolations: vec![]
798 })
799 );
800 test_error_kind!(
801 string_invalid_unicode_code_point,
802 r#""\u{110000}""#,
803 SyntaxErrorKind::InvalidUnicodeCodePoint(0x110000)
804 );
805 test_error_kind!(
806 string_missing_unicode_code_point_opening_brace,
807 r#""\u41}""#,
808 SyntaxErrorKind::NomError(nom::error::ErrorKind::Tag)
809 );
810 test_error_kind!(
811 string_missing_unicode_code_point_closing_brace,
812 r#""\u{41""#,
813 SyntaxErrorKind::NomError(nom::error::ErrorKind::Tag)
814 );
815 test_error_kind!(
816 string_invalid_hex_digit,
817 r#""\xGG""#,
818 SyntaxErrorKind::InvalidHexDigit
819 );
820 test_error_kind!(
821 string_invalid_unicode_code_point_hex,
822 r#""\u{GG}""#,
823 SyntaxErrorKind::InvalidHexDigit
824 );
825 test_expression!(
826 string_interpolation,
827 r#""{42}""#,
828 Expression::String(StringLiteral {
829 value: "".into(),
830 interpolations: vec![(0, Box::new(Expression::Number("42".into())))]
831 })
832 );
833 test_expression!(
834 string_interpolation_with_text,
835 r#""Hello, {42}!""#,
836 Expression::String(StringLiteral {
837 value: "Hello, !".into(),
838 interpolations: vec![(7, Box::new(Expression::Number("42".into())))]
839 })
840 );
841 test_expression!(
842 string_newline,
843 r#""
844""#,
845 Expression::String(StringLiteral {
846 value: "\n".into(),
847 interpolations: vec![]
848 })
849 );
850
851 macro_rules! test_binary_expression {
852 ($input:expr, $expected:expr) => {
853 let (input, result) = parse_expression($input).unwrap();
854 assert_eq!(input, "");
855 assert_eq!(dbg!(result).to_string(), $expected);
856 };
857 }
858
859 #[test]
860 fn test_binary_expression() {
861 test_binary_expression!("1 + 2 * 3", "(1 + (2 * 3))");
862 test_binary_expression!("2 * 3 + 4", "((2 * 3) + 4)");
863 test_binary_expression!("2 ** 3 * 4", "((2 ** 3) * 4)");
864 test_binary_expression!("2 * 3 ** 4", "(2 * (3 ** 4))");
865
866 test_binary_expression!("1 + 2 + 3", "((1 + 2) + 3)"); test_binary_expression!("2 ** 3 ** 2", "(2 ** (3 ** 2))"); test_binary_expression!("10 / 5 / 2", "((10 / 5) / 2)"); test_binary_expression!("-2 * 3", "((-2) * 3)");
873 test_binary_expression!("!1 && 2", "((!1) && 2)");
874 test_binary_expression!("~1 & 2", "((~1) & 2)");
875
876 test_binary_expression!("1 | 2 & 3", "(1 | (2 & 3))");
878 test_binary_expression!("1 & 2 ^ 3", "((1 & 2) ^ 3)");
879 test_binary_expression!("1 | 2 | 3", "((1 | 2) | 3)");
880
881 test_binary_expression!("1 || 2 && 3", "(1 || (2 && 3))");
883 test_binary_expression!("1 && 2 || 3 && 4", "((1 && 2) || (3 && 4))");
884
885 test_binary_expression!("1 < 2 == 3 > 4", "((1 < 2) == (3 > 4))");
887 test_binary_expression!("1 == 2 != 3 == 4", "(((1 == 2) != 3) == 4)");
888
889 test_binary_expression!("1 << 2 + 3", "(1 << (2 + 3))");
891 test_binary_expression!("1 + 2 >> 3", "((1 + 2) >> 3)");
892
893 test_binary_expression!("1 |> 2 |> 3", "((1 |> 2) |> 3)");
895
896 test_binary_expression!("1 + 2 * 3 ** 4", "(1 + (2 * (3 ** 4)))");
898 test_binary_expression!(
899 "1 || 2 && 3 | 4 ^ 5 & 6",
900 "(1 || (2 && (3 | (4 ^ (5 & 6)))))"
901 );
902 test_binary_expression!(
903 "1 + 2 * 3 < 4 && 5 == 6",
904 "(((1 + (2 * 3)) < 4) && (5 == 6))"
905 );
906 }
907}