1use std::fmt::Display;
20use std::iter::FusedIterator;
21use std::ops::Range;
22use thiserror::Error;
23
24#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
29#[non_exhaustive]
30pub enum Value {
31 Integer(i64),
32}
33
34impl Display for Value {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Value::Integer(i) => i.fmt(f),
38 }
39 }
40}
41
42#[derive(Clone, Debug, Eq, Hash, PartialEq)]
44pub enum Term<'a> {
45 Value(Value),
47 Variable {
49 name: &'a str,
51 location: Range<usize>,
53 },
54}
55
56#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
58pub enum Operator {
59 Question,
61 Colon,
63 Bar,
65 BarBar,
67 BarEqual,
69 Caret,
71 CaretEqual,
73 And,
75 AndAnd,
77 AndEqual,
79 Equal,
81 EqualEqual,
83 Bang,
85 BangEqual,
87 Less,
89 LessEqual,
91 LessLess,
93 LessLessEqual,
95 Greater,
97 GreaterEqual,
99 GreaterGreater,
101 GreaterGreaterEqual,
103 Plus,
105 PlusPlus,
107 PlusEqual,
109 Minus,
111 MinusMinus,
113 MinusEqual,
115 Asterisk,
117 AsteriskEqual,
119 Slash,
121 SlashEqual,
123 Percent,
125 PercentEqual,
127 Tilde,
129 OpenParen,
131 CloseParen,
133}
134
135#[derive(Clone, Debug, Eq, Hash, PartialEq)]
137pub enum TokenValue<'a> {
138 Term(Term<'a>),
140 Operator(Operator),
142 EndOfInput,
144}
145
146#[derive(Clone, Debug, Eq, Hash, PartialEq)]
148pub struct Token<'a> {
149 pub value: TokenValue<'a>,
151 pub location: Range<usize>,
153}
154
155#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
157#[non_exhaustive]
158pub enum TokenError {
159 #[error("invalid numeric constant")]
161 InvalidNumericConstant,
162
163 #[error("invalid character")]
166 InvalidCharacter,
167}
168
169#[derive(Clone, Debug, Eq, Hash, PartialEq)]
171pub struct Error {
172 pub cause: TokenError,
174 pub location: Range<usize>,
176}
177
178const OPERATORS: &[(&str, Operator)] = &[
184 ("?", Operator::Question),
185 (":", Operator::Colon),
186 ("|=", Operator::BarEqual),
187 ("||", Operator::BarBar),
188 ("|", Operator::Bar),
189 ("^=", Operator::CaretEqual),
190 ("^", Operator::Caret),
191 ("&=", Operator::AndEqual),
192 ("&&", Operator::AndAnd),
193 ("&", Operator::And),
194 ("==", Operator::EqualEqual),
195 ("=", Operator::Equal),
196 ("!=", Operator::BangEqual),
197 ("<=", Operator::LessEqual),
198 ("<<=", Operator::LessLessEqual),
199 ("<<", Operator::LessLess),
200 ("<", Operator::Less),
201 (">=", Operator::GreaterEqual),
202 (">>=", Operator::GreaterGreaterEqual),
203 (">>", Operator::GreaterGreater),
204 (">", Operator::Greater),
205 ("+=", Operator::PlusEqual),
206 ("++", Operator::PlusPlus),
207 ("+", Operator::Plus),
208 ("-=", Operator::MinusEqual),
209 ("--", Operator::MinusMinus),
210 ("-", Operator::Minus),
211 ("*=", Operator::AsteriskEqual),
212 ("*", Operator::Asterisk),
213 ("/=", Operator::SlashEqual),
214 ("/", Operator::Slash),
215 ("%=", Operator::PercentEqual),
216 ("%", Operator::Percent),
217 ("~", Operator::Tilde),
218 ("!", Operator::Bang),
219 ("(", Operator::OpenParen),
220 (")", Operator::CloseParen),
221];
222
223#[derive(Clone, Debug, Eq, Hash, PartialEq)]
232pub struct Tokens<'a> {
233 source: &'a str,
234 index: usize,
235}
236
237impl<'a> Tokens<'a> {
238 pub fn new(source: &'a str) -> Self {
240 Tokens { source, index: 0 }
241 }
242
243 pub fn next_token(&mut self) -> Result<Token<'a>, Error> {
244 let source = self.source[self.index..].trim_start();
245 let start_of_token = self.source.len() - source.len();
246 let first_char = if let Some(c) = source.chars().next() {
247 c
248 } else {
249 return Ok(Token {
250 value: TokenValue::EndOfInput,
251 location: start_of_token..start_of_token,
252 });
253 };
254
255 if let Some((lexeme, operator)) = OPERATORS
256 .iter()
257 .copied()
258 .find(|&(lexeme, _)| source.starts_with(lexeme))
259 {
260 let end_of_token = start_of_token + lexeme.len();
262 let location = start_of_token..end_of_token;
263 self.index = end_of_token;
264 Ok(Token {
265 value: TokenValue::Operator(operator),
266 location,
267 })
268 } else {
269 let remainder = source.trim_start_matches(|c: char| c.is_alphanumeric() || c == '_');
271 let token_len = source.len() - remainder.len();
272 if token_len == 0 {
273 return Err(Error {
274 cause: TokenError::InvalidCharacter,
275 location: start_of_token..start_of_token + 1,
276 });
277 }
278 let end_of_token = start_of_token + token_len;
279 let location = start_of_token..end_of_token;
280 let token = &source[..token_len];
281 let term = if first_char.is_ascii_digit() {
282 let parse = if let Some(token_source) = token.strip_prefix("0X") {
283 i64::from_str_radix(token_source, 0x10)
284 } else if let Some(token_source) = token.strip_prefix("0x") {
285 i64::from_str_radix(token_source, 0x10)
286 } else if source.starts_with('0') {
287 i64::from_str_radix(token, 0o10)
288 } else {
289 token.parse()
290 };
291 match parse {
292 Ok(i) => Term::Value(Value::Integer(i)),
293 Err(_) => {
294 return Err(Error {
295 cause: TokenError::InvalidNumericConstant,
296 location,
297 });
298 }
299 }
300 } else {
301 Term::Variable {
302 name: token,
303 location: location.clone(),
304 }
305 };
306
307 self.index = end_of_token;
308 Ok(Token {
309 value: TokenValue::Term(term),
310 location,
311 })
312 }
313 }
314}
315
316impl<'a> Iterator for Tokens<'a> {
317 type Item = Result<Token<'a>, Error>;
318
319 fn next(&mut self) -> Option<Result<Token<'a>, Error>> {
320 Some(self.next_token())
321 }
322}
323
324impl FusedIterator for Tokens<'_> {}
326
327#[derive(Clone, Debug, Eq, Hash, PartialEq)]
332pub struct PeekableTokens<'a> {
333 inner: Tokens<'a>,
334 cached_next: Option<Result<Token<'a>, Error>>,
335}
336
337impl<'a> PeekableTokens<'a> {
338 pub fn new(inner: Tokens<'a>) -> Self {
340 let cached_next = None;
341 PeekableTokens { inner, cached_next }
342 }
343
344 pub fn next(&mut self) -> Result<Token<'a>, Error> {
346 self.cached_next
347 .take()
348 .unwrap_or_else(|| self.inner.next_token())
349 }
350
351 pub fn peek(&mut self) -> &Result<Token<'a>, Error> {
356 self.cached_next
357 .get_or_insert_with(|| self.inner.next_token())
358 }
359}
360
361impl<'a> From<&'a str> for PeekableTokens<'a> {
362 fn from(source: &'a str) -> Self {
363 PeekableTokens::new(Tokens::new(source))
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn decimal_integer_constants() {
373 assert_eq!(
374 Tokens::new("1").next(),
375 Some(Ok(Token {
376 value: TokenValue::Term(Term::Value(Value::Integer(1))),
377 location: 0..1,
378 }))
379 );
380 assert_eq!(
381 Tokens::new("42").next(),
382 Some(Ok(Token {
383 value: TokenValue::Term(Term::Value(Value::Integer(42))),
384 location: 0..2,
385 }))
386 );
387 }
388
389 #[test]
390 fn invalid_digit_in_decimal_constant() {
391 assert_eq!(
392 Tokens::new("1a").next(),
393 Some(Err(Error {
394 cause: TokenError::InvalidNumericConstant,
395 location: 0..2,
396 }))
397 );
398 assert_eq!(
399 Tokens::new(" 123_456 ").next(),
400 Some(Err(Error {
401 cause: TokenError::InvalidNumericConstant,
402 location: 2..9,
403 }))
404 );
405 }
406
407 #[test]
408 fn octal_integer_constants() {
409 assert_eq!(
410 Tokens::new("0").next(),
411 Some(Ok(Token {
412 value: TokenValue::Term(Term::Value(Value::Integer(0))),
413 location: 0..1,
414 }))
415 );
416 assert_eq!(
417 Tokens::new("01").next(),
418 Some(Ok(Token {
419 value: TokenValue::Term(Term::Value(Value::Integer(0o1))),
420 location: 0..2,
421 }))
422 );
423 assert_eq!(
424 Tokens::new("07").next(),
425 Some(Ok(Token {
426 value: TokenValue::Term(Term::Value(Value::Integer(0o7))),
427 location: 0..2,
428 }))
429 );
430 assert_eq!(
431 Tokens::new("0123").next(),
432 Some(Ok(Token {
433 value: TokenValue::Term(Term::Value(Value::Integer(0o123))),
434 location: 0..4,
435 }))
436 );
437 }
438
439 #[test]
440 fn invalid_digit_in_octal_constant() {
441 assert_eq!(
442 Tokens::new("08").next(),
443 Some(Err(Error {
444 cause: TokenError::InvalidNumericConstant,
445 location: 0..2,
446 }))
447 );
448 assert_eq!(
449 Tokens::new(" 0192 ").next(),
450 Some(Err(Error {
451 cause: TokenError::InvalidNumericConstant,
452 location: 1..5,
453 }))
454 );
455 assert_eq!(
456 Tokens::new("0ab").next(),
457 Some(Err(Error {
458 cause: TokenError::InvalidNumericConstant,
459 location: 0..3,
460 }))
461 );
462 }
463
464 #[test]
465 fn hexadecimal_integer_constants() {
466 assert_eq!(
467 Tokens::new("0x0").next(),
468 Some(Ok(Token {
469 value: TokenValue::Term(Term::Value(Value::Integer(0x0))),
470 location: 0..3,
471 }))
472 );
473 assert_eq!(
474 Tokens::new("0X1").next(),
475 Some(Ok(Token {
476 value: TokenValue::Term(Term::Value(Value::Integer(0x1))),
477 location: 0..3,
478 }))
479 );
480 assert_eq!(
481 Tokens::new("0x19Af").next(),
482 Some(Ok(Token {
483 value: TokenValue::Term(Term::Value(Value::Integer(0x19AF))),
484 location: 0..6,
485 }))
486 );
487 }
488
489 #[test]
490 fn broken_hexadecimal_integer_constants() {
491 assert_eq!(
492 Tokens::new("0x").next(),
493 Some(Err(Error {
494 cause: TokenError::InvalidNumericConstant,
495 location: 0..2,
496 }))
497 );
498 assert_eq!(
499 Tokens::new(" 0xG ").next(),
500 Some(Err(Error {
501 cause: TokenError::InvalidNumericConstant,
502 location: 1..4,
503 }))
504 );
505 assert_eq!(
506 Tokens::new("0x1z2").next(),
507 Some(Err(Error {
508 cause: TokenError::InvalidNumericConstant,
509 location: 0..5,
510 }))
511 );
512 }
513
514 #[test]
517 fn variables() {
518 assert_eq!(
519 Tokens::new("abc").next(),
520 Some(Ok(Token {
521 value: TokenValue::Term(Term::Variable {
522 name: "abc",
523 location: 0..3,
524 }),
525 location: 0..3,
526 }))
527 );
528 assert_eq!(
529 Tokens::new("foo_BAR").next(),
530 Some(Ok(Token {
531 value: TokenValue::Term(Term::Variable {
532 name: "foo_BAR",
533 location: 0..7,
534 }),
535 location: 0..7,
536 }))
537 );
538 assert_eq!(
539 Tokens::new("a1B2c").next(),
540 Some(Ok(Token {
541 value: TokenValue::Term(Term::Variable {
542 name: "a1B2c",
543 location: 0..5,
544 }),
545 location: 0..5,
546 }))
547 );
548 assert_eq!(
549 Tokens::new(" _var").next(),
550 Some(Ok(Token {
551 value: TokenValue::Term(Term::Variable {
552 name: "_var",
553 location: 1..5,
554 }),
555 location: 1..5,
556 }))
557 );
558 }
559
560 #[test]
561 fn operators() {
562 assert_eq!(
563 Tokens::new("?").next(),
564 Some(Ok(Token {
565 value: TokenValue::Operator(Operator::Question),
566 location: 0..1,
567 }))
568 );
569 assert_eq!(
570 Tokens::new(":").next(),
571 Some(Ok(Token {
572 value: TokenValue::Operator(Operator::Colon),
573 location: 0..1,
574 }))
575 );
576 assert_eq!(
577 Tokens::new("|").next(),
578 Some(Ok(Token {
579 value: TokenValue::Operator(Operator::Bar),
580 location: 0..1,
581 }))
582 );
583 assert_eq!(
584 Tokens::new("||").next(),
585 Some(Ok(Token {
586 value: TokenValue::Operator(Operator::BarBar),
587 location: 0..2,
588 }))
589 );
590 assert_eq!(
591 Tokens::new("|=").next(),
592 Some(Ok(Token {
593 value: TokenValue::Operator(Operator::BarEqual),
594 location: 0..2,
595 }))
596 );
597 assert_eq!(
598 Tokens::new("^").next(),
599 Some(Ok(Token {
600 value: TokenValue::Operator(Operator::Caret),
601 location: 0..1,
602 }))
603 );
604 assert_eq!(
605 Tokens::new("^=").next(),
606 Some(Ok(Token {
607 value: TokenValue::Operator(Operator::CaretEqual),
608 location: 0..2,
609 }))
610 );
611 assert_eq!(
612 Tokens::new("&").next(),
613 Some(Ok(Token {
614 value: TokenValue::Operator(Operator::And),
615 location: 0..1,
616 }))
617 );
618 assert_eq!(
619 Tokens::new("&&").next(),
620 Some(Ok(Token {
621 value: TokenValue::Operator(Operator::AndAnd),
622 location: 0..2,
623 }))
624 );
625 assert_eq!(
626 Tokens::new("&=").next(),
627 Some(Ok(Token {
628 value: TokenValue::Operator(Operator::AndEqual),
629 location: 0..2,
630 }))
631 );
632 assert_eq!(
633 Tokens::new("=").next(),
634 Some(Ok(Token {
635 value: TokenValue::Operator(Operator::Equal),
636 location: 0..1,
637 }))
638 );
639 assert_eq!(
640 Tokens::new("==").next(),
641 Some(Ok(Token {
642 value: TokenValue::Operator(Operator::EqualEqual),
643 location: 0..2,
644 }))
645 );
646 assert_eq!(
647 Tokens::new("!=").next(),
648 Some(Ok(Token {
649 value: TokenValue::Operator(Operator::BangEqual),
650 location: 0..2,
651 }))
652 );
653 assert_eq!(
654 Tokens::new("<").next(),
655 Some(Ok(Token {
656 value: TokenValue::Operator(Operator::Less),
657 location: 0..1,
658 }))
659 );
660 assert_eq!(
661 Tokens::new("<=").next(),
662 Some(Ok(Token {
663 value: TokenValue::Operator(Operator::LessEqual),
664 location: 0..2,
665 }))
666 );
667 assert_eq!(
668 Tokens::new("<<").next(),
669 Some(Ok(Token {
670 value: TokenValue::Operator(Operator::LessLess),
671 location: 0..2,
672 }))
673 );
674 assert_eq!(
675 Tokens::new("<<=").next(),
676 Some(Ok(Token {
677 value: TokenValue::Operator(Operator::LessLessEqual),
678 location: 0..3,
679 }))
680 );
681 assert_eq!(
682 Tokens::new(">").next(),
683 Some(Ok(Token {
684 value: TokenValue::Operator(Operator::Greater),
685 location: 0..1,
686 }))
687 );
688 assert_eq!(
689 Tokens::new(">=").next(),
690 Some(Ok(Token {
691 value: TokenValue::Operator(Operator::GreaterEqual),
692 location: 0..2,
693 }))
694 );
695 assert_eq!(
696 Tokens::new(">>").next(),
697 Some(Ok(Token {
698 value: TokenValue::Operator(Operator::GreaterGreater),
699 location: 0..2,
700 }))
701 );
702 assert_eq!(
703 Tokens::new(">>=").next(),
704 Some(Ok(Token {
705 value: TokenValue::Operator(Operator::GreaterGreaterEqual),
706 location: 0..3,
707 }))
708 );
709 assert_eq!(
710 Tokens::new("+").next(),
711 Some(Ok(Token {
712 value: TokenValue::Operator(Operator::Plus),
713 location: 0..1,
714 }))
715 );
716 assert_eq!(
717 Tokens::new("++").next(),
718 Some(Ok(Token {
719 value: TokenValue::Operator(Operator::PlusPlus),
720 location: 0..2,
721 }))
722 );
723 assert_eq!(
724 Tokens::new("+=").next(),
725 Some(Ok(Token {
726 value: TokenValue::Operator(Operator::PlusEqual),
727 location: 0..2,
728 }))
729 );
730 assert_eq!(
731 Tokens::new("-").next(),
732 Some(Ok(Token {
733 value: TokenValue::Operator(Operator::Minus),
734 location: 0..1,
735 }))
736 );
737 assert_eq!(
738 Tokens::new("--").next(),
739 Some(Ok(Token {
740 value: TokenValue::Operator(Operator::MinusMinus),
741 location: 0..2,
742 }))
743 );
744 assert_eq!(
745 Tokens::new("-=").next(),
746 Some(Ok(Token {
747 value: TokenValue::Operator(Operator::MinusEqual),
748 location: 0..2,
749 }))
750 );
751 assert_eq!(
752 Tokens::new("*").next(),
753 Some(Ok(Token {
754 value: TokenValue::Operator(Operator::Asterisk),
755 location: 0..1,
756 }))
757 );
758 assert_eq!(
759 Tokens::new("*=").next(),
760 Some(Ok(Token {
761 value: TokenValue::Operator(Operator::AsteriskEqual),
762 location: 0..2,
763 }))
764 );
765 assert_eq!(
766 Tokens::new("/").next(),
767 Some(Ok(Token {
768 value: TokenValue::Operator(Operator::Slash),
769 location: 0..1,
770 }))
771 );
772 assert_eq!(
773 Tokens::new("/=").next(),
774 Some(Ok(Token {
775 value: TokenValue::Operator(Operator::SlashEqual),
776 location: 0..2,
777 }))
778 );
779 assert_eq!(
780 Tokens::new("%").next(),
781 Some(Ok(Token {
782 value: TokenValue::Operator(Operator::Percent),
783 location: 0..1,
784 }))
785 );
786 assert_eq!(
787 Tokens::new("%=").next(),
788 Some(Ok(Token {
789 value: TokenValue::Operator(Operator::PercentEqual),
790 location: 0..2,
791 }))
792 );
793 assert_eq!(
794 Tokens::new("~").next(),
795 Some(Ok(Token {
796 value: TokenValue::Operator(Operator::Tilde),
797 location: 0..1,
798 }))
799 );
800 assert_eq!(
801 Tokens::new("!").next(),
802 Some(Ok(Token {
803 value: TokenValue::Operator(Operator::Bang),
804 location: 0..1,
805 }))
806 );
807 assert_eq!(
808 Tokens::new("(").next(),
809 Some(Ok(Token {
810 value: TokenValue::Operator(Operator::OpenParen),
811 location: 0..1
812 }))
813 );
814 assert_eq!(
815 Tokens::new("(").next(),
816 Some(Ok(Token {
817 value: TokenValue::Operator(Operator::OpenParen),
818 location: 0..1
819 }))
820 );
821 }
822
823 #[test]
824 fn space_around_token() {
825 assert_eq!(
826 Tokens::new(" 42").next(),
827 Some(Ok(Token {
828 value: TokenValue::Term(Term::Value(Value::Integer(42))),
829 location: 1..3,
830 }))
831 );
832 assert_eq!(
833 Tokens::new("042 ").next(),
834 Some(Ok(Token {
835 value: TokenValue::Term(Term::Value(Value::Integer(0o42))),
836 location: 0..3,
837 }))
838 );
839 assert_eq!(
840 Tokens::new("\t 123 \n").next(),
841 Some(Ok(Token {
842 value: TokenValue::Term(Term::Value(Value::Integer(123))),
843 location: 2..5,
844 }))
845 );
846 }
847
848 #[test]
849 fn parsing_two_tokens() {
850 let mut tokens = Tokens::new(" 123 foo ");
851 assert_eq!(
852 tokens.next(),
853 Some(Ok(Token {
854 value: TokenValue::Term(Term::Value(Value::Integer(123))),
855 location: 1..4,
856 }))
857 );
858 assert_eq!(
859 tokens.next(),
860 Some(Ok(Token {
861 value: TokenValue::Term(Term::Variable {
862 name: "foo",
863 location: 6..9,
864 }),
865 location: 6..9,
866 }))
867 );
868 assert_eq!(
869 tokens.next(),
870 Some(Ok(Token {
871 value: TokenValue::EndOfInput,
872 location: 10..10,
873 }))
874 );
875 }
876
877 #[test]
878 fn parsing_many_tokens() {
879 let mut tokens = Tokens::new(" 10+0 ");
881 assert_eq!(
882 tokens.next(),
883 Some(Ok(Token {
884 value: TokenValue::Term(Term::Value(Value::Integer(10))),
885 location: 1..3,
886 }))
887 );
888 assert_eq!(
889 tokens.next(),
890 Some(Ok(Token {
891 value: TokenValue::Operator(Operator::Plus),
892 location: 3..4,
893 }))
894 );
895 assert_eq!(
896 tokens.next(),
897 Some(Ok(Token {
898 value: TokenValue::Term(Term::Value(Value::Integer(0))),
899 location: 4..5,
900 }))
901 );
902 assert_eq!(
903 tokens.next(),
904 Some(Ok(Token {
905 value: TokenValue::EndOfInput,
906 location: 6..6,
907 }))
908 );
909 }
910
911 #[test]
912 fn parsing_adjacent_operators() {
913 let mut tokens = Tokens::new("+-0");
914 assert_eq!(
915 tokens.next(),
916 Some(Ok(Token {
917 value: TokenValue::Operator(Operator::Plus),
918 location: 0..1,
919 }))
920 );
921 assert_eq!(
922 tokens.next(),
923 Some(Ok(Token {
924 value: TokenValue::Operator(Operator::Minus),
925 location: 1..2,
926 }))
927 );
928 assert_eq!(
929 tokens.next(),
930 Some(Ok(Token {
931 value: TokenValue::Term(Term::Value(Value::Integer(0))),
932 location: 2..3,
933 }))
934 );
935 assert_eq!(
936 tokens.next(),
937 Some(Ok(Token {
938 value: TokenValue::EndOfInput,
939 location: 3..3,
940 }))
941 );
942 }
943
944 #[test]
945 fn unrecognized_character() {
946 assert_eq!(
947 Tokens::new("#").next(),
948 Some(Err(Error {
949 cause: TokenError::InvalidCharacter,
950 location: 0..1,
951 }))
952 );
953 assert_eq!(
954 Tokens::new(" @@").next(),
955 Some(Err(Error {
956 cause: TokenError::InvalidCharacter,
957 location: 1..2,
958 }))
959 );
960 }
961
962 #[test]
963 fn peekable_tokens() {
964 let mut tokens = PeekableTokens::from("1 + 2");
965 assert_eq!(
966 tokens.peek(),
967 &Ok(Token {
968 value: TokenValue::Term(Term::Value(Value::Integer(1))),
969 location: 0..1,
970 })
971 );
972 assert_eq!(
973 tokens.peek(),
974 &Ok(Token {
975 value: TokenValue::Term(Term::Value(Value::Integer(1))),
976 location: 0..1,
977 })
978 );
979 assert_eq!(
980 tokens.next(),
981 Ok(Token {
982 value: TokenValue::Term(Term::Value(Value::Integer(1))),
983 location: 0..1,
984 })
985 );
986
987 assert_eq!(
988 tokens.peek(),
989 &Ok(Token {
990 value: TokenValue::Operator(Operator::Plus),
991 location: 2..3,
992 })
993 );
994 assert_eq!(
995 tokens.next(),
996 Ok(Token {
997 value: TokenValue::Operator(Operator::Plus),
998 location: 2..3,
999 })
1000 );
1001
1002 assert_eq!(
1003 tokens.next(),
1004 Ok(Token {
1005 value: TokenValue::Term(Term::Value(Value::Integer(2))),
1006 location: 4..5,
1007 })
1008 );
1009
1010 assert_eq!(
1011 tokens.peek(),
1012 &Ok(Token {
1013 value: TokenValue::EndOfInput,
1014 location: 5..5,
1015 })
1016 );
1017 assert_eq!(
1018 tokens.next(),
1019 Ok(Token {
1020 value: TokenValue::EndOfInput,
1021 location: 5..5,
1022 })
1023 );
1024 }
1025}