1use crate::token::Operator;
20use crate::token::PeekableTokens;
21use crate::token::Term;
22use crate::token::Token;
23use crate::token::TokenError;
24use crate::token::TokenValue;
25use std::ops::Range;
26use thiserror::Error;
27
28#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
33pub enum PrefixOperator {
34 Increment,
36 Decrement,
38 NumericCoercion,
40 NumericNegation,
42 LogicalNegation,
44 BitwiseNegation,
46}
47
48#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
50pub enum PostfixOperator {
51 Increment,
53 Decrement,
55}
56
57#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
59pub enum BinaryOperator {
60 Assign,
62 LogicalOr,
64 LogicalAnd,
66 BitwiseOr,
68 BitwiseOrAssign,
70 BitwiseXor,
72 BitwiseXorAssign,
74 BitwiseAnd,
76 BitwiseAndAssign,
78 EqualTo,
80 NotEqualTo,
82 LessThan,
84 GreaterThan,
86 LessThanOrEqualTo,
88 GreaterThanOrEqualTo,
90 ShiftLeft,
92 ShiftLeftAssign,
94 ShiftRight,
96 ShiftRightAssign,
98 Add,
100 AddAssign,
102 Subtract,
104 SubtractAssign,
106 Multiply,
108 MultiplyAssign,
110 Divide,
112 DivideAssign,
114 Remainder,
116 RemainderAssign,
118}
119
120#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
122enum Associativity {
123 Left,
124 Right,
125}
126
127impl Operator {
128 fn as_prefix(self) -> Option<PrefixOperator> {
129 match self {
130 Operator::PlusPlus => Some(PrefixOperator::Increment),
131 Operator::MinusMinus => Some(PrefixOperator::Decrement),
132 Operator::Plus => Some(PrefixOperator::NumericCoercion),
133 Operator::Minus => Some(PrefixOperator::NumericNegation),
134 Operator::Bang => Some(PrefixOperator::LogicalNegation),
135 Operator::Tilde => Some(PrefixOperator::BitwiseNegation),
136 _ => None,
137 }
138 }
139
140 fn as_postfix(self) -> Option<PostfixOperator> {
141 match self {
142 Operator::PlusPlus => Some(PostfixOperator::Increment),
143 Operator::MinusMinus => Some(PostfixOperator::Decrement),
144 _ => None,
145 }
146 }
147
148 fn as_binary(self) -> Option<(BinaryOperator, Associativity)> {
149 use Associativity::*;
150 use BinaryOperator::*;
151 match self {
152 Operator::Equal => Some((Assign, Right)),
153 Operator::BarEqual => Some((BitwiseOrAssign, Right)),
154 Operator::CaretEqual => Some((BitwiseXorAssign, Right)),
155 Operator::AndEqual => Some((BitwiseAndAssign, Right)),
156 Operator::LessLessEqual => Some((ShiftLeftAssign, Right)),
157 Operator::GreaterGreaterEqual => Some((ShiftRightAssign, Right)),
158 Operator::PlusEqual => Some((AddAssign, Right)),
159 Operator::MinusEqual => Some((SubtractAssign, Right)),
160 Operator::AsteriskEqual => Some((MultiplyAssign, Right)),
161 Operator::SlashEqual => Some((DivideAssign, Right)),
162 Operator::PercentEqual => Some((RemainderAssign, Right)),
163 Operator::BarBar => Some((LogicalOr, Left)),
164 Operator::AndAnd => Some((LogicalAnd, Left)),
165 Operator::Bar => Some((BitwiseOr, Left)),
166 Operator::Caret => Some((BitwiseXor, Left)),
167 Operator::And => Some((BitwiseAnd, Left)),
168 Operator::EqualEqual => Some((EqualTo, Left)),
169 Operator::BangEqual => Some((NotEqualTo, Left)),
170 Operator::Less => Some((LessThan, Left)),
171 Operator::LessEqual => Some((LessThanOrEqualTo, Left)),
172 Operator::Greater => Some((GreaterThan, Left)),
173 Operator::GreaterEqual => Some((GreaterThanOrEqualTo, Left)),
174 Operator::LessLess => Some((ShiftLeft, Left)),
175 Operator::GreaterGreater => Some((ShiftRight, Left)),
176 Operator::Plus => Some((Add, Left)),
177 Operator::Minus => Some((Subtract, Left)),
178 Operator::Asterisk => Some((Multiply, Left)),
179 Operator::Slash => Some((Divide, Left)),
180 Operator::Percent => Some((Remainder, Left)),
181 _ => None,
182 }
183 }
184
185 fn precedence(self) -> u8 {
190 use Operator::*;
191 match self {
192 CloseParen | Colon => 0,
193 Equal | BarEqual | CaretEqual | AndEqual | LessLessEqual | GreaterGreaterEqual
194 | PlusEqual | MinusEqual | AsteriskEqual | SlashEqual | PercentEqual => 1,
195 Question => 2,
196 BarBar => 3,
197 AndAnd => 4,
198 Bar => 5,
199 Caret => 6,
200 And => 7,
201 EqualEqual | BangEqual => 8,
202 Less | LessEqual | Greater | GreaterEqual => 9,
203 LessLess | GreaterGreater => 10,
204 Plus | Minus => 11,
205 Asterisk | Slash | Percent => 12,
206 Tilde | Bang | PlusPlus | MinusMinus | OpenParen => 13,
207 }
208 }
209}
210
211#[derive(Clone, Debug, Eq, Hash, PartialEq)]
218pub enum Ast<'a> {
219 Term(Term<'a>),
221 Prefix {
225 operator: PrefixOperator,
227 location: Range<usize>,
229 },
230 Postfix {
234 operator: PostfixOperator,
236 location: Range<usize>,
238 },
239 Binary {
244 operator: BinaryOperator,
246 rhs_len: usize,
248 location: Range<usize>,
250 },
251 Conditional {
257 then_len: usize,
259 else_len: usize,
261 },
262}
263
264#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
266pub enum SyntaxError {
267 #[error(transparent)]
269 TokenError(#[from] TokenError),
270 #[error("incomplete expression")]
272 IncompleteExpression,
273 #[error("expected an operator")]
275 MissingOperator,
276 #[error("closing parenthesis missing")]
278 UnclosedParenthesis {
279 opening_location: Range<usize>,
281 },
282 #[error("expected `:`")]
284 QuestionWithoutColon {
285 question_location: Range<usize>,
287 },
288 #[error("`:` without matching `?`")]
290 ColonWithoutQuestion,
291 #[error("invalid use of operator")]
293 InvalidOperator,
294}
295
296#[derive(Clone, Debug, Eq, Hash, PartialEq)]
298pub struct Error {
299 pub cause: SyntaxError,
301 pub location: Range<usize>,
303}
304
305impl From<crate::token::Error> for Error {
306 fn from(e: crate::token::Error) -> Self {
307 Error {
308 cause: e.cause.into(),
309 location: e.location,
310 }
311 }
312}
313
314fn parse_postfix<'a>(
316 tokens: &mut PeekableTokens<'a>,
317 result: &mut Vec<Ast<'a>>,
318) -> Result<(), Error> {
319 while let &Ok(Token {
320 value: TokenValue::Operator(operator),
321 ..
322 }) = tokens.peek()
323 {
324 let operator = match operator.as_postfix() {
325 Some(operator) => operator,
326 None => break,
327 };
328 let location = tokens.next().unwrap().location;
329 result.push(Ast::Postfix { operator, location });
330 }
331 Ok(())
332}
333
334fn parse_close_paren(
338 tokens: &mut PeekableTokens,
339 opening_location: Range<usize>,
340) -> Result<(), Error> {
341 let token = tokens.next()?;
342 match token.value {
343 TokenValue::Operator(Operator::CloseParen) => Ok(()),
344
345 TokenValue::Operator(Operator::Colon) => Err(Error {
346 cause: SyntaxError::ColonWithoutQuestion,
347 location: token.location,
348 }),
349
350 _ => Err(Error {
351 cause: SyntaxError::UnclosedParenthesis { opening_location },
352 location: token.location,
353 }),
354 }
355}
356
357fn parse_leaf<'a>(tokens: &mut PeekableTokens<'a>, result: &mut Vec<Ast<'a>>) -> Result<(), Error> {
362 let token = tokens.next()?;
363 match token.value {
364 TokenValue::Term(term) => {
365 result.push(Ast::Term(term));
366 parse_postfix(tokens, result)
367 }
368
369 TokenValue::Operator(Operator::OpenParen) => {
370 parse_tree(tokens, 1, result)?;
371 parse_close_paren(tokens, token.location)?;
372 parse_postfix(tokens, result)
373 }
374
375 TokenValue::Operator(operator) => {
376 let operator = match operator.as_prefix() {
377 Some(operator) => operator,
378 None => {
379 return Err(Error {
380 cause: SyntaxError::InvalidOperator,
381 location: token.location,
382 })
383 }
384 };
385 parse_leaf(tokens, result)?;
386 result.push(Ast::Prefix {
387 operator,
388 location: token.location,
389 });
390 Ok(())
391 }
392
393 TokenValue::EndOfInput => Err(Error {
394 cause: SyntaxError::IncompleteExpression,
395 location: token.location,
396 }),
397 }
398}
399
400fn parse_binary_rhs<'a>(
403 tokens: &mut PeekableTokens<'a>,
404 operator: BinaryOperator,
405 location: Range<usize>,
406 min_precedence: u8,
407 result: &mut Vec<Ast<'a>>,
408) -> Result<(), Error> {
409 let old_len = result.len();
410 parse_tree(tokens, min_precedence, result)?;
411 result.push(Ast::Binary {
412 operator,
413 rhs_len: result.len() - old_len,
414 location,
415 });
416 Ok(())
417}
418
419fn parse_tree<'a>(
424 tokens: &mut PeekableTokens<'a>,
425 min_precedence: u8,
426 result: &mut Vec<Ast<'a>>,
427) -> Result<(), Error> {
428 parse_leaf(tokens, result)?;
429
430 while let &Ok(Token {
431 value: TokenValue::Operator(operator),
432 ..
433 }) = tokens.peek()
434 {
435 let precedence = operator.precedence();
436 if precedence < min_precedence {
437 break;
438 }
439
440 let location = tokens.next().unwrap().location;
441
442 use Operator::*;
443 if operator == Question {
444 let then_index = result.len();
445 parse_tree(tokens, 1, result)?;
446
447 let token = tokens.next()?;
449 if token.value != TokenValue::Operator(Operator::Colon) {
450 return Err(Error {
451 cause: SyntaxError::QuestionWithoutColon {
452 question_location: location,
453 },
454 location: token.location,
455 });
456 }
457
458 let else_index = result.len();
459 parse_tree(tokens, precedence, result)?;
460
461 result.push(Ast::Conditional {
462 then_len: else_index - then_index,
463 else_len: result.len() - else_index,
464 });
465 continue;
466 }
467
468 let (operator, rhs_precedence) = match operator.as_binary() {
469 Some((operator, Associativity::Left)) => (operator, precedence + 1),
470 Some((operator, Associativity::Right)) => (operator, precedence),
471 None => {
472 return Err(Error {
473 cause: SyntaxError::InvalidOperator,
474 location,
475 })
476 }
477 };
478 parse_binary_rhs(tokens, operator, location, rhs_precedence, result)?
479 }
480 Ok(())
481}
482
483fn parse_end_of_input(tokens: &mut PeekableTokens) -> Result<(), Error> {
487 let token = tokens.next()?;
488 match token.value {
489 TokenValue::EndOfInput => Ok(()),
490
491 TokenValue::Operator(Operator::Colon) => Err(Error {
492 cause: SyntaxError::ColonWithoutQuestion,
493 location: token.location,
494 }),
495
496 _ => Err(Error {
497 cause: SyntaxError::MissingOperator,
498 location: token.location,
499 }),
500 }
501}
502
503pub fn parse(mut tokens: PeekableTokens) -> Result<Vec<Ast>, Error> {
508 let mut result = Vec::new();
509 parse_tree(&mut tokens, 1, &mut result)?;
510 parse_end_of_input(&mut tokens)?;
511 Ok(result)
512}
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517 use crate::token::Value;
518
519 fn parse_str(source: &str) -> Result<Vec<Ast>, Error> {
520 parse(PeekableTokens::from(source))
521 }
522
523 #[test]
524 fn term() {
525 assert_eq!(
526 parse_str("123").unwrap(),
527 [Ast::Term(Term::Value(Value::Integer(123)))]
528 );
529 assert_eq!(
530 parse_str("0x42").unwrap(),
531 [Ast::Term(Term::Value(Value::Integer(0x42)))]
532 );
533 assert_eq!(
534 parse_str(" foo ").unwrap(),
535 [Ast::Term(Term::Variable {
536 name: "foo",
537 location: 1..4
538 })]
539 );
540 }
541
542 #[test]
543 fn token_error_in_term() {
544 assert_eq!(
545 parse_str("08"),
546 Err(Error {
547 cause: SyntaxError::TokenError(TokenError::InvalidNumericConstant),
548 location: 0..2
549 })
550 );
551 }
552
553 #[test]
554 fn increment_postfix_operator() {
555 assert_eq!(
556 parse_str("a++").unwrap(),
557 [
558 Ast::Term(Term::Variable {
559 name: "a",
560 location: 0..1,
561 }),
562 Ast::Postfix {
563 operator: PostfixOperator::Increment,
564 location: 1..3,
565 },
566 ]
567 );
568 }
569
570 #[test]
571 fn decrement_postfix_operator() {
572 assert_eq!(
573 parse_str("a--").unwrap(),
574 [
575 Ast::Term(Term::Variable {
576 name: "a",
577 location: 0..1,
578 }),
579 Ast::Postfix {
580 operator: PostfixOperator::Decrement,
581 location: 1..3,
582 },
583 ]
584 );
585 }
586
587 #[test]
588 fn combination_of_postfix_operators() {
589 assert_eq!(
590 parse_str(" x ++ -- ++ ").unwrap(),
591 [
592 Ast::Term(Term::Variable {
593 name: "x",
594 location: 1..2,
595 }),
596 Ast::Postfix {
597 operator: PostfixOperator::Increment,
598 location: 3..5,
599 },
600 Ast::Postfix {
601 operator: PostfixOperator::Decrement,
602 location: 7..9,
603 },
604 Ast::Postfix {
605 operator: PostfixOperator::Increment,
606 location: 10..12,
607 },
608 ]
609 );
610 }
611
612 #[test]
613 fn increment_prefix_operator() {
614 assert_eq!(
615 parse_str("++a").unwrap(),
616 [
617 Ast::Term(Term::Variable {
618 name: "a",
619 location: 2..3,
620 }),
621 Ast::Prefix {
622 operator: PrefixOperator::Increment,
623 location: 0..2,
624 },
625 ]
626 );
627 }
628
629 #[test]
630 fn decrement_prefix_operator() {
631 assert_eq!(
632 parse_str("--a").unwrap(),
633 [
634 Ast::Term(Term::Variable {
635 name: "a",
636 location: 2..3,
637 }),
638 Ast::Prefix {
639 operator: PrefixOperator::Decrement,
640 location: 0..2,
641 },
642 ]
643 );
644 }
645
646 #[test]
647 fn numeric_coercion_prefix_operator() {
648 assert_eq!(
649 parse_str("+a").unwrap(),
650 [
651 Ast::Term(Term::Variable {
652 name: "a",
653 location: 1..2,
654 }),
655 Ast::Prefix {
656 operator: PrefixOperator::NumericCoercion,
657 location: 0..1,
658 },
659 ]
660 );
661 }
662
663 #[test]
664 fn numeric_negation_prefix_operator() {
665 assert_eq!(
666 parse_str("-a").unwrap(),
667 [
668 Ast::Term(Term::Variable {
669 name: "a",
670 location: 1..2,
671 }),
672 Ast::Prefix {
673 operator: PrefixOperator::NumericNegation,
674 location: 0..1,
675 },
676 ]
677 );
678 }
679
680 #[test]
681 fn logical_negation_prefix_operator() {
682 assert_eq!(
683 parse_str("!a").unwrap(),
684 [
685 Ast::Term(Term::Variable {
686 name: "a",
687 location: 1..2,
688 }),
689 Ast::Prefix {
690 operator: PrefixOperator::LogicalNegation,
691 location: 0..1,
692 },
693 ]
694 );
695 }
696
697 #[test]
698 fn bitwise_negation_prefix_operator() {
699 assert_eq!(
700 parse_str("~a").unwrap(),
701 [
702 Ast::Term(Term::Variable {
703 name: "a",
704 location: 1..2,
705 }),
706 Ast::Prefix {
707 operator: PrefixOperator::BitwiseNegation,
708 location: 0..1,
709 },
710 ]
711 );
712 }
713
714 #[test]
715 fn combination_of_prefix_operators() {
716 assert_eq!(
717 parse_str(" - + ! ~ ++ -- i ").unwrap(),
718 [
719 Ast::Term(Term::Variable {
720 name: "i",
721 location: 16..17,
722 }),
723 Ast::Prefix {
724 operator: PrefixOperator::Decrement,
725 location: 13..15,
726 },
727 Ast::Prefix {
728 operator: PrefixOperator::Increment,
729 location: 10..12,
730 },
731 Ast::Prefix {
732 operator: PrefixOperator::BitwiseNegation,
733 location: 8..9,
734 },
735 Ast::Prefix {
736 operator: PrefixOperator::LogicalNegation,
737 location: 5..6,
738 },
739 Ast::Prefix {
740 operator: PrefixOperator::NumericCoercion,
741 location: 3..4,
742 },
743 Ast::Prefix {
744 operator: PrefixOperator::NumericNegation,
745 location: 1..2,
746 },
747 ]
748 );
749 }
750
751 #[test]
752 fn combination_of_unary_and_binary_operators() {
753 assert_eq!(
754 parse_str("0 + + a ++ * !1").unwrap(),
755 [
756 Ast::Term(Term::Value(Value::Integer(0))),
757 Ast::Term(Term::Variable {
758 name: "a",
759 location: 6..7,
760 }),
761 Ast::Postfix {
762 operator: PostfixOperator::Increment,
763 location: 8..10,
764 },
765 Ast::Prefix {
766 operator: PrefixOperator::NumericCoercion,
767 location: 4..5,
768 },
769 Ast::Term(Term::Value(Value::Integer(1))),
770 Ast::Prefix {
771 operator: PrefixOperator::LogicalNegation,
772 location: 13..14,
773 },
774 Ast::Binary {
775 operator: BinaryOperator::Multiply,
776 rhs_len: 2,
777 location: 11..12,
778 },
779 Ast::Binary {
780 operator: BinaryOperator::Add,
781 rhs_len: 6,
782 location: 2..3,
783 },
784 ]
785 );
786 }
787
788 #[test]
789 fn simple_assignment_operator() {
790 assert_eq!(
791 parse_str("a=42").unwrap(),
792 [
793 Ast::Term(Term::Variable {
794 name: "a",
795 location: 0..1,
796 }),
797 Ast::Term(Term::Value(Value::Integer(42))),
798 Ast::Binary {
799 operator: BinaryOperator::Assign,
800 rhs_len: 1,
801 location: 1..2,
802 },
803 ]
804 );
805 }
806
807 #[test]
808 fn bitwise_or_assign_operator() {
809 assert_eq!(
810 parse_str("b|=2").unwrap(),
811 [
812 Ast::Term(Term::Variable {
813 name: "b",
814 location: 0..1,
815 }),
816 Ast::Term(Term::Value(Value::Integer(2))),
817 Ast::Binary {
818 operator: BinaryOperator::BitwiseOrAssign,
819 rhs_len: 1,
820 location: 1..3,
821 },
822 ]
823 );
824 }
825
826 #[test]
827 fn bitwise_xor_assign_operator() {
828 assert_eq!(
829 parse_str("c^=3").unwrap(),
830 [
831 Ast::Term(Term::Variable {
832 name: "c",
833 location: 0..1,
834 }),
835 Ast::Term(Term::Value(Value::Integer(3))),
836 Ast::Binary {
837 operator: BinaryOperator::BitwiseXorAssign,
838 rhs_len: 1,
839 location: 1..3,
840 },
841 ]
842 );
843 }
844
845 #[test]
846 fn bitwise_and_assign_operator() {
847 assert_eq!(
848 parse_str("d&=5").unwrap(),
849 [
850 Ast::Term(Term::Variable {
851 name: "d",
852 location: 0..1,
853 }),
854 Ast::Term(Term::Value(Value::Integer(5))),
855 Ast::Binary {
856 operator: BinaryOperator::BitwiseAndAssign,
857 rhs_len: 1,
858 location: 1..3,
859 },
860 ]
861 );
862 }
863
864 #[test]
865 fn shift_left_assign_operator() {
866 assert_eq!(
867 parse_str("e<<=7").unwrap(),
868 [
869 Ast::Term(Term::Variable {
870 name: "e",
871 location: 0..1,
872 }),
873 Ast::Term(Term::Value(Value::Integer(7))),
874 Ast::Binary {
875 operator: BinaryOperator::ShiftLeftAssign,
876 rhs_len: 1,
877 location: 1..4,
878 },
879 ]
880 );
881 }
882
883 #[test]
884 fn shift_right_assign_operator() {
885 assert_eq!(
886 parse_str("f>>=11").unwrap(),
887 [
888 Ast::Term(Term::Variable {
889 name: "f",
890 location: 0..1,
891 }),
892 Ast::Term(Term::Value(Value::Integer(11))),
893 Ast::Binary {
894 operator: BinaryOperator::ShiftRightAssign,
895 rhs_len: 1,
896 location: 1..4,
897 },
898 ]
899 );
900 }
901
902 #[test]
903 fn add_assign_operator() {
904 assert_eq!(
905 parse_str("g+=13").unwrap(),
906 [
907 Ast::Term(Term::Variable {
908 name: "g",
909 location: 0..1,
910 }),
911 Ast::Term(Term::Value(Value::Integer(13))),
912 Ast::Binary {
913 operator: BinaryOperator::AddAssign,
914 rhs_len: 1,
915 location: 1..3,
916 },
917 ]
918 );
919 }
920
921 #[test]
922 fn subtract_assign_operator() {
923 assert_eq!(
924 parse_str("h-=17").unwrap(),
925 [
926 Ast::Term(Term::Variable {
927 name: "h",
928 location: 0..1,
929 }),
930 Ast::Term(Term::Value(Value::Integer(17))),
931 Ast::Binary {
932 operator: BinaryOperator::SubtractAssign,
933 rhs_len: 1,
934 location: 1..3,
935 },
936 ]
937 );
938 }
939
940 #[test]
941 fn multiply_assign_operator() {
942 assert_eq!(
943 parse_str("i*=19").unwrap(),
944 [
945 Ast::Term(Term::Variable {
946 name: "i",
947 location: 0..1,
948 }),
949 Ast::Term(Term::Value(Value::Integer(19))),
950 Ast::Binary {
951 operator: BinaryOperator::MultiplyAssign,
952 rhs_len: 1,
953 location: 1..3,
954 },
955 ]
956 );
957 }
958
959 #[test]
960 fn divide_assign_operator() {
961 assert_eq!(
962 parse_str("j/=23").unwrap(),
963 [
964 Ast::Term(Term::Variable {
965 name: "j",
966 location: 0..1,
967 }),
968 Ast::Term(Term::Value(Value::Integer(23))),
969 Ast::Binary {
970 operator: BinaryOperator::DivideAssign,
971 rhs_len: 1,
972 location: 1..3,
973 },
974 ]
975 );
976 }
977
978 #[test]
979 fn remainder_assign_operator() {
980 assert_eq!(
981 parse_str("k%=29").unwrap(),
982 [
983 Ast::Term(Term::Variable {
984 name: "k",
985 location: 0..1,
986 }),
987 Ast::Term(Term::Value(Value::Integer(29))),
988 Ast::Binary {
989 operator: BinaryOperator::RemainderAssign,
990 rhs_len: 1,
991 location: 1..3,
992 },
993 ]
994 );
995 }
996
997 #[test]
998 fn assignment_operators_are_right_associative() {
999 assert_eq!(
1000 parse_str(" a = b |= c ^= d &= e <<= f >>= g += h -= i *= j /= k %= m ").unwrap(),
1001 [
1002 Ast::Term(Term::Variable {
1003 name: "a",
1004 location: 1..2,
1005 }),
1006 Ast::Term(Term::Variable {
1007 name: "b",
1008 location: 5..6,
1009 }),
1010 Ast::Term(Term::Variable {
1011 name: "c",
1012 location: 10..11,
1013 }),
1014 Ast::Term(Term::Variable {
1015 name: "d",
1016 location: 15..16,
1017 }),
1018 Ast::Term(Term::Variable {
1019 name: "e",
1020 location: 20..21,
1021 }),
1022 Ast::Term(Term::Variable {
1023 name: "f",
1024 location: 26..27,
1025 }),
1026 Ast::Term(Term::Variable {
1027 name: "g",
1028 location: 32..33,
1029 }),
1030 Ast::Term(Term::Variable {
1031 name: "h",
1032 location: 37..38,
1033 }),
1034 Ast::Term(Term::Variable {
1035 name: "i",
1036 location: 42..43,
1037 }),
1038 Ast::Term(Term::Variable {
1039 name: "j",
1040 location: 47..48,
1041 }),
1042 Ast::Term(Term::Variable {
1043 name: "k",
1044 location: 52..53,
1045 }),
1046 Ast::Term(Term::Variable {
1047 name: "m",
1048 location: 57..58,
1049 }),
1050 Ast::Binary {
1051 operator: BinaryOperator::RemainderAssign,
1052 rhs_len: 1,
1053 location: 54..56,
1054 },
1055 Ast::Binary {
1056 operator: BinaryOperator::DivideAssign,
1057 rhs_len: 3,
1058 location: 49..51,
1059 },
1060 Ast::Binary {
1061 operator: BinaryOperator::MultiplyAssign,
1062 rhs_len: 5,
1063 location: 44..46,
1064 },
1065 Ast::Binary {
1066 operator: BinaryOperator::SubtractAssign,
1067 rhs_len: 7,
1068 location: 39..41,
1069 },
1070 Ast::Binary {
1071 operator: BinaryOperator::AddAssign,
1072 rhs_len: 9,
1073 location: 34..36,
1074 },
1075 Ast::Binary {
1076 operator: BinaryOperator::ShiftRightAssign,
1077 rhs_len: 11,
1078 location: 28..31,
1079 },
1080 Ast::Binary {
1081 operator: BinaryOperator::ShiftLeftAssign,
1082 rhs_len: 13,
1083 location: 22..25,
1084 },
1085 Ast::Binary {
1086 operator: BinaryOperator::BitwiseAndAssign,
1087 rhs_len: 15,
1088 location: 17..19,
1089 },
1090 Ast::Binary {
1091 operator: BinaryOperator::BitwiseXorAssign,
1092 rhs_len: 17,
1093 location: 12..14,
1094 },
1095 Ast::Binary {
1096 operator: BinaryOperator::BitwiseOrAssign,
1097 rhs_len: 19,
1098 location: 7..9,
1099 },
1100 Ast::Binary {
1101 operator: BinaryOperator::Assign,
1102 rhs_len: 21,
1103 location: 3..4,
1104 },
1105 ]
1106 );
1107 }
1108
1109 #[test]
1110 fn logical_or_operator() {
1111 assert_eq!(
1112 parse_str("3||5").unwrap(),
1113 [
1114 Ast::Term(Term::Value(Value::Integer(3))),
1115 Ast::Term(Term::Value(Value::Integer(5))),
1116 Ast::Binary {
1117 operator: BinaryOperator::LogicalOr,
1118 rhs_len: 1,
1119 location: 1..3,
1120 },
1121 ]
1122 );
1123 }
1124
1125 #[test]
1126 fn logical_or_operator_is_left_associative() {
1127 assert_eq!(
1128 parse_str("1||2||3").unwrap(),
1129 [
1130 Ast::Term(Term::Value(Value::Integer(1))),
1131 Ast::Term(Term::Value(Value::Integer(2))),
1132 Ast::Binary {
1133 operator: BinaryOperator::LogicalOr,
1134 rhs_len: 1,
1135 location: 1..3,
1136 },
1137 Ast::Term(Term::Value(Value::Integer(3))),
1138 Ast::Binary {
1139 operator: BinaryOperator::LogicalOr,
1140 rhs_len: 1,
1141 location: 4..6,
1142 },
1143 ]
1144 );
1145 }
1146
1147 #[test]
1148 fn logical_or_operator_in_conditional_operator() {
1149 assert_eq!(
1150 parse_str("1||2?3:4||5").unwrap(),
1151 [
1152 Ast::Term(Term::Value(Value::Integer(1))),
1153 Ast::Term(Term::Value(Value::Integer(2))),
1154 Ast::Binary {
1155 operator: BinaryOperator::LogicalOr,
1156 rhs_len: 1,
1157 location: 1..3,
1158 },
1159 Ast::Term(Term::Value(Value::Integer(3))),
1160 Ast::Term(Term::Value(Value::Integer(4))),
1161 Ast::Term(Term::Value(Value::Integer(5))),
1162 Ast::Binary {
1163 operator: BinaryOperator::LogicalOr,
1164 rhs_len: 1,
1165 location: 8..10,
1166 },
1167 Ast::Conditional {
1168 then_len: 1,
1169 else_len: 3,
1170 },
1171 ]
1172 );
1173 }
1174
1175 #[test]
1176 fn logical_and_operator() {
1177 assert_eq!(
1178 parse_str("3&&5").unwrap(),
1179 [
1180 Ast::Term(Term::Value(Value::Integer(3))),
1181 Ast::Term(Term::Value(Value::Integer(5))),
1182 Ast::Binary {
1183 operator: BinaryOperator::LogicalAnd,
1184 rhs_len: 1,
1185 location: 1..3,
1186 },
1187 ]
1188 );
1189 }
1190
1191 #[test]
1192 fn logical_and_operator_is_left_associative() {
1193 assert_eq!(
1194 parse_str("1&&2&&3").unwrap(),
1195 [
1196 Ast::Term(Term::Value(Value::Integer(1))),
1197 Ast::Term(Term::Value(Value::Integer(2))),
1198 Ast::Binary {
1199 operator: BinaryOperator::LogicalAnd,
1200 rhs_len: 1,
1201 location: 1..3,
1202 },
1203 Ast::Term(Term::Value(Value::Integer(3))),
1204 Ast::Binary {
1205 operator: BinaryOperator::LogicalAnd,
1206 rhs_len: 1,
1207 location: 4..6,
1208 },
1209 ]
1210 );
1211 }
1212
1213 #[test]
1214 fn logical_and_operator_in_logical_or_operator() {
1215 assert_eq!(
1216 parse_str("1&&2||3&&4").unwrap(),
1217 [
1218 Ast::Term(Term::Value(Value::Integer(1))),
1219 Ast::Term(Term::Value(Value::Integer(2))),
1220 Ast::Binary {
1221 operator: BinaryOperator::LogicalAnd,
1222 rhs_len: 1,
1223 location: 1..3,
1224 },
1225 Ast::Term(Term::Value(Value::Integer(3))),
1226 Ast::Term(Term::Value(Value::Integer(4))),
1227 Ast::Binary {
1228 operator: BinaryOperator::LogicalAnd,
1229 rhs_len: 1,
1230 location: 7..9,
1231 },
1232 Ast::Binary {
1233 operator: BinaryOperator::LogicalOr,
1234 rhs_len: 3,
1235 location: 4..6,
1236 },
1237 ]
1238 );
1239 }
1240
1241 #[test]
1242 fn multiplication_operator_in_addition_operator() {
1243 assert_eq!(
1244 parse_str("1*2+3*4").unwrap(),
1245 [
1246 Ast::Term(Term::Value(Value::Integer(1))),
1247 Ast::Term(Term::Value(Value::Integer(2))),
1248 Ast::Binary {
1249 operator: BinaryOperator::Multiply,
1250 rhs_len: 1,
1251 location: 1..2,
1252 },
1253 Ast::Term(Term::Value(Value::Integer(3))),
1254 Ast::Term(Term::Value(Value::Integer(4))),
1255 Ast::Binary {
1256 operator: BinaryOperator::Multiply,
1257 rhs_len: 1,
1258 location: 5..6,
1259 },
1260 Ast::Binary {
1261 operator: BinaryOperator::Add,
1262 rhs_len: 3,
1263 location: 3..4,
1264 },
1265 ]
1266 );
1267 }
1268
1269 #[test]
1270 fn multiplication_division_remainder_operators_are_left_associative() {
1271 assert_eq!(
1272 parse_str("1*2/3%4").unwrap(),
1273 [
1274 Ast::Term(Term::Value(Value::Integer(1))),
1275 Ast::Term(Term::Value(Value::Integer(2))),
1276 Ast::Binary {
1277 operator: BinaryOperator::Multiply,
1278 rhs_len: 1,
1279 location: 1..2,
1280 },
1281 Ast::Term(Term::Value(Value::Integer(3))),
1282 Ast::Binary {
1283 operator: BinaryOperator::Divide,
1284 rhs_len: 1,
1285 location: 3..4,
1286 },
1287 Ast::Term(Term::Value(Value::Integer(4))),
1288 Ast::Binary {
1289 operator: BinaryOperator::Remainder,
1290 rhs_len: 1,
1291 location: 5..6,
1292 },
1293 ]
1294 );
1295 }
1296
1297 #[test]
1298 fn conditional_operator() {
1299 assert_eq!(
1300 parse_str("1?2:3").unwrap(),
1301 [
1302 Ast::Term(Term::Value(Value::Integer(1))),
1303 Ast::Term(Term::Value(Value::Integer(2))),
1304 Ast::Term(Term::Value(Value::Integer(3))),
1305 Ast::Conditional {
1306 then_len: 1,
1307 else_len: 1,
1308 },
1309 ]
1310 );
1311 }
1312
1313 #[test]
1314 fn assignment_in_then_value() {
1315 assert_eq!(
1316 parse_str("a ? b = 0 : 1").unwrap(),
1317 [
1318 Ast::Term(Term::Variable {
1319 name: "a",
1320 location: 0..1,
1321 }),
1322 Ast::Term(Term::Variable {
1323 name: "b",
1324 location: 4..5,
1325 }),
1326 Ast::Term(Term::Value(Value::Integer(0))),
1327 Ast::Binary {
1328 operator: BinaryOperator::Assign,
1329 rhs_len: 1,
1330 location: 6..7,
1331 },
1332 Ast::Term(Term::Value(Value::Integer(1))),
1333 Ast::Conditional {
1334 then_len: 3,
1335 else_len: 1,
1336 },
1337 ]
1338 );
1339 }
1340
1341 #[test]
1342 fn condition_in_assignment() {
1343 assert_eq!(
1344 parse_str("4 ? a : b = 5").unwrap(),
1345 [
1346 Ast::Term(Term::Value(Value::Integer(4))),
1347 Ast::Term(Term::Variable {
1348 name: "a",
1349 location: 4..5,
1350 }),
1351 Ast::Term(Term::Variable {
1352 name: "b",
1353 location: 8..9,
1354 }),
1355 Ast::Conditional {
1356 then_len: 1,
1357 else_len: 1,
1358 },
1359 Ast::Term(Term::Value(Value::Integer(5))),
1360 Ast::Binary {
1361 operator: BinaryOperator::Assign,
1362 rhs_len: 1,
1363 location: 10..11,
1364 },
1365 ]
1366 );
1367 }
1368
1369 #[test]
1370 fn conditional_operator_is_right_associative() {
1371 assert_eq!(
1372 parse_str("5 ? 6 : 7 ? 8 : 9").unwrap(),
1373 [
1374 Ast::Term(Term::Value(Value::Integer(5))),
1375 Ast::Term(Term::Value(Value::Integer(6))),
1376 Ast::Term(Term::Value(Value::Integer(7))),
1377 Ast::Term(Term::Value(Value::Integer(8))),
1378 Ast::Term(Term::Value(Value::Integer(9))),
1379 Ast::Conditional {
1380 then_len: 1,
1381 else_len: 1,
1382 },
1383 Ast::Conditional {
1384 then_len: 1,
1385 else_len: 4,
1386 },
1387 ]
1388 );
1389 }
1390
1391 #[test]
1392 fn question_without_colon() {
1393 assert_eq!(
1394 parse_str(" 1 ? 2 + 3 "),
1395 Err(Error {
1396 cause: SyntaxError::QuestionWithoutColon {
1397 question_location: 3..4,
1398 },
1399 location: 11..11,
1400 })
1401 );
1402 assert_eq!(
1403 parse_str("(9?8)"),
1404 Err(Error {
1405 cause: SyntaxError::QuestionWithoutColon {
1406 question_location: 2..3,
1407 },
1408 location: 4..5,
1409 })
1410 );
1411 }
1412
1413 #[test]
1414 fn colon_without_question() {
1415 assert_eq!(
1416 parse_str(" 2 : 3 "),
1417 Err(Error {
1418 cause: SyntaxError::ColonWithoutQuestion,
1419 location: 3..4,
1420 })
1421 );
1422 assert_eq!(
1423 parse_str("(4+5-6:7)"),
1424 Err(Error {
1425 cause: SyntaxError::ColonWithoutQuestion,
1426 location: 6..7,
1427 })
1428 );
1429 }
1430
1431 #[test]
1432 fn parentheses() {
1433 assert_eq!(
1434 parse_str("(a = 0)--").unwrap(),
1435 [
1436 Ast::Term(Term::Variable {
1437 name: "a",
1438 location: 1..2,
1439 }),
1440 Ast::Term(Term::Value(Value::Integer(0))),
1441 Ast::Binary {
1442 operator: BinaryOperator::Assign,
1443 rhs_len: 1,
1444 location: 3..4,
1445 },
1446 Ast::Postfix {
1447 operator: PostfixOperator::Decrement,
1448 location: 7..9,
1449 },
1450 ]
1451 );
1452 }
1453
1454 #[test]
1455 fn unmatched_parentheses() {
1456 assert_eq!(
1457 parse_str("(a + 0 "),
1458 Err(Error {
1459 cause: SyntaxError::UnclosedParenthesis {
1460 opening_location: 0..1,
1461 },
1462 location: 7..7,
1463 })
1464 );
1465 assert_eq!(
1466 parse_str(" ((0)"),
1467 Err(Error {
1468 cause: SyntaxError::UnclosedParenthesis {
1469 opening_location: 1..2,
1470 },
1471 location: 5..5,
1472 })
1473 );
1474 }
1475
1476 #[test]
1477 fn incomplete_expression() {
1478 assert_eq!(
1479 parse_str(" "),
1480 Err(Error {
1481 cause: SyntaxError::IncompleteExpression,
1482 location: 3..3,
1483 })
1484 );
1485 assert_eq!(
1486 parse_str("+"),
1487 Err(Error {
1488 cause: SyntaxError::IncompleteExpression,
1489 location: 1..1,
1490 })
1491 );
1492 }
1493
1494 #[test]
1495 fn invalid_operator() {
1496 assert_eq!(
1497 parse_str(" 3 ! 5"),
1498 Err(Error {
1499 cause: SyntaxError::InvalidOperator,
1500 location: 3..4,
1501 })
1502 );
1503 assert_eq!(
1504 parse_str(" 1 + 2 ~ 3 + 4 "),
1505 Err(Error {
1506 cause: SyntaxError::InvalidOperator,
1507 location: 7..8,
1508 })
1509 );
1510 assert_eq!(
1511 parse_str(" + * 3 "),
1512 Err(Error {
1513 cause: SyntaxError::InvalidOperator,
1514 location: 3..4,
1515 })
1516 );
1517 }
1518
1519 #[test]
1520 fn redundant_tokens() {
1521 assert_eq!(
1522 parse_str(" 1 22 "),
1523 Err(Error {
1524 cause: SyntaxError::MissingOperator,
1525 location: 3..5,
1526 })
1527 );
1528 }
1529}