1use crate::Lexer;
2use crate::SyntaxError;
3use crate::lexer::{Token, TokenType};
4use miette::SourceSpan;
5use serde::Serialize;
6use serde::ser::SerializeStruct;
7use std::borrow::Cow;
8use std::fmt;
9
10pub struct Parser<'src> {
14 input: &'src str,
15 lexer: Lexer<'src>,
16}
17
18impl<'src> Parser<'src> {
19 pub fn new(input: &'src str) -> Self {
21 Self {
22 input,
23 lexer: Lexer::new(input),
24 }
25 }
26
27 pub fn parse(&mut self) -> Result<TokenTree<'src>, SyntaxError> {
29 self.parse_expr(0)
30 }
31
32 fn parse_expr(
33 &mut self,
34 min_bp: u8,
35 ) -> Result<TokenTree<'src>, SyntaxError> {
36 let lhs = match self.lexer.next() {
37 Some(Ok(token)) => token,
38 None => return Ok(TokenTree::Atom(Atom::Null)), Some(Err(e)) => return Err(e),
40 };
41
42 let mut lhs = match lhs {
43 Token {
45 ty: TokenType::Ident,
46 origin,
47 ..
48 } => TokenTree::Atom(Atom::Ident(origin)),
49 Token {
50 ty: TokenType::Int(n),
51 ..
52 } => TokenTree::Atom(Atom::Int(n)),
53 Token {
54 ty: TokenType::Uint(n),
55 ..
56 } => TokenTree::Atom(Atom::Uint(n)),
57 Token {
58 ty: TokenType::Double(n),
59 ..
60 } => TokenTree::Atom(Atom::Double(n)),
61 Token {
62 ty: TokenType::Null,
63 ..
64 } => TokenTree::Atom(Atom::Null),
65 Token {
66 ty: TokenType::String | TokenType::RawString,
67 origin,
68 ..
69 } => TokenTree::Atom(Atom::String(Token::unescape(origin))),
70 Token {
71 ty: TokenType::Bytes | TokenType::RawBytes,
72 origin,
73 ..
74 } => TokenTree::Atom(Atom::Bytes(Token::unescape_bytes(origin))),
75 Token {
76 ty: TokenType::True,
77 ..
78 } => TokenTree::Atom(Atom::Bool(true)),
79 Token {
80 ty: TokenType::False,
81 ..
82 } => TokenTree::Atom(Atom::Bool(false)),
83
84 Token {
86 ty: TokenType::Dyn, ..
87 } => {
88 self.lexer.expect(
89 TokenType::LeftParen,
90 "Expected opening parenthesis after dyn",
91 )?;
92 let expr = self.parse_expr(0)?;
93 self.lexer.expect(
94 TokenType::RightParen,
95 "Expected closing parenthesis after dyn",
96 )?;
97 TokenTree::Cons(Op::Dyn, vec![expr])
98 }
99
100 Token {
102 ty: TokenType::LeftParen,
103 ..
104 } => {
105 let lhs = self.parse_expr(0)?;
106 self.lexer.expect(
107 TokenType::RightParen,
108 "Expected closing parenthesis",
109 )?;
110 TokenTree::Cons(Op::Group, vec![lhs])
111 }
112
113 Token {
115 ty: TokenType::Not | TokenType::Minus,
116 ..
117 } => {
118 let op = match lhs.ty {
119 TokenType::Not => Op::Not,
120 TokenType::Minus => Op::Minus,
121 _ => unreachable!(),
122 };
123 let ((), r_bp) = prefix_binding_power(op);
124 let rhs = self.parse_expr(r_bp)?;
125 TokenTree::Cons(op, vec![rhs])
126 }
127
128 Token {
130 ty: TokenType::LeftBrace,
131 ..
132 } => self.parse_map()?,
133
134 Token {
135 ty: TokenType::LeftBracket,
136 ..
137 } => self.parse_list()?,
138
139 token => {
140 return Err(SyntaxError::new(
141 self.input.to_string(),
142 SourceSpan::new(token.offset.into(), token.span_len),
143 format!("Unexpected token: {:?}", token),
144 )
145 .with_help("Expected an expression"));
146 }
147 };
148
149 loop {
150 let op = self.lexer.peek();
151 if op.is_some_and(|op| op.is_err()) {
152 return Err(self
153 .lexer
154 .next()
155 .expect("checked Some above")
156 .expect_err("checked Err above"));
157 }
158
159 let op = match op
160 .map(|res| res.as_ref().expect("handled Err above"))
161 {
162 None
163 | Some(Token {
164 ty:
165 TokenType::RightParen
166 | TokenType::RightBracket
167 | TokenType::RightBrace
168 | TokenType::Comma
169 | TokenType::Colon
170 | TokenType::Semicolon,
171 ..
172 }) => break,
173 Some(Token {
174 ty: TokenType::LeftParen,
175 ..
176 }) => Op::Call,
177 Some(Token {
178 ty: TokenType::LeftBracket,
179 ..
180 }) => Op::Index,
181 Some(Token {
182 ty: TokenType::Dot, ..
183 }) => Op::Field,
184 Some(Token {
185 ty: TokenType::Minus,
186 ..
187 }) => Op::Minus,
188 Some(Token {
189 ty: TokenType::Plus,
190 ..
191 }) => Op::Plus,
192 Some(Token {
193 ty: TokenType::Star,
194 ..
195 }) => Op::Multiply,
196 Some(Token {
197 ty: TokenType::Percent,
198 ..
199 }) => Op::Mod,
200 Some(Token {
201 ty: TokenType::NotEqual,
202 ..
203 }) => Op::NotEqual,
204 Some(Token {
205 ty: TokenType::In, ..
206 }) => Op::In,
207 Some(Token {
208 ty: TokenType::EqualEqual,
209 ..
210 }) => Op::EqualEqual,
211 Some(Token {
212 ty: TokenType::LessEqual,
213 ..
214 }) => Op::LessEqual,
215 Some(Token {
216 ty: TokenType::GreaterEqual,
217 ..
218 }) => Op::GreaterEqual,
219 Some(Token {
220 ty: TokenType::Less,
221 ..
222 }) => Op::Less,
223 Some(Token {
224 ty: TokenType::Greater,
225 ..
226 }) => Op::Greater,
227 Some(Token {
228 ty: TokenType::Slash,
229 ..
230 }) => Op::Devide,
231 Some(Token {
232 ty: TokenType::And, ..
233 }) => Op::And,
234 Some(Token {
235 ty: TokenType::Or, ..
236 }) => Op::Or,
237 Some(Token {
238 ty: TokenType::QuestionMark,
239 ..
240 }) => Op::IfTernary,
241
242 Some(token) => {
243 return Err(SyntaxError::new(
244 self.input.to_string(),
245 SourceSpan::new(token.offset.into(), token.span_len),
246 format!("Unexpected token: {:?}", token),
247 )
248 .with_help("Expected an operator"));
249 }
250 };
251
252 if let Some((l_bp, ())) = postfix_binding_power(op) {
253 if l_bp < min_bp {
254 break;
255 }
256 self.lexer.next();
257
258 lhs = match op {
259 Op::Call => TokenTree::Call {
260 func: Box::new(lhs),
261 args: self.parse_fn_call_args()?,
262 is_method: false,
263 },
264 Op::Index => {
265 let index = self.parse_expr(0)?;
266 self.lexer.expect(
267 TokenType::RightBracket,
268 "Expected closing bracket",
269 )?;
270 TokenTree::Cons(op, vec![lhs, index])
271 }
272 _ => TokenTree::Cons(op, vec![lhs]),
273 };
274 continue;
275 }
276
277 if let Some((l_bp, r_bp)) = infix_binding_power(op) {
278 if l_bp < min_bp {
279 break;
280 }
281 self.lexer.next();
282
283 lhs = match op {
284 Op::IfTernary => {
285 let mhs = self.parse_expr(0)?;
286 self.lexer.expect(
287 TokenType::Colon,
288 "Expected colon after the condition",
289 )?;
290 let rhs = self.parse_expr(r_bp)?;
291 TokenTree::Cons(op, vec![lhs, mhs, rhs])
292 }
293 Op::Field => {
294 let rhs = self.parse_expr(r_bp)?;
295 match rhs {
296 TokenTree::Call {
297 func,
298 mut args,
299 is_method,
300 } => {
301 if !is_method {
302 TokenTree::Call {
303 func,
304 args: vec![lhs]
305 .into_iter()
306 .chain(args)
307 .collect(),
308 is_method: true,
309 }
310 } else if args.is_empty() {
311 args.insert(0, lhs);
312 TokenTree::Call {
313 func,
314 args,
315 is_method: true,
316 }
317 } else {
318 let access = args.remove(0);
319 let receiver = Self::attach_method_receiver(
320 lhs, access,
321 );
322 args.insert(0, receiver);
323 TokenTree::Call {
324 func,
325 args,
326 is_method,
327 }
328 }
329 }
330 rhs => Self::chain_field_access(lhs, rhs),
331 }
332 }
333 _ => {
334 let rhs = self.parse_expr(r_bp)?;
335 TokenTree::Cons(op, vec![lhs, rhs])
336 }
337 };
338
339 continue;
340 }
341
342 break;
343 }
344
345 Ok(lhs)
346 }
347
348 fn attach_method_receiver(
349 lhs: TokenTree<'src>,
350 receiver: TokenTree<'src>,
351 ) -> TokenTree<'src> {
352 match receiver {
353 TokenTree::Call {
354 func,
355 args,
356 is_method: false,
357 } => TokenTree::Call {
358 func,
359 args: std::iter::once(lhs).chain(args).collect(),
360 is_method: true,
361 },
362 TokenTree::Call {
363 func,
364 mut args,
365 is_method: true,
366 } => {
367 if args.is_empty() {
368 args.insert(0, lhs);
369 TokenTree::Call {
370 func,
371 args,
372 is_method: true,
373 }
374 } else {
375 let nested = args.remove(0);
376 let updated = Self::attach_method_receiver(lhs, nested);
377 args.insert(0, updated);
378 TokenTree::Call {
379 func,
380 args,
381 is_method: true,
382 }
383 }
384 }
385 other => Self::chain_field_access(lhs, other),
386 }
387 }
388
389 fn chain_field_access(
390 lhs: TokenTree<'src>,
391 rhs: TokenTree<'src>,
392 ) -> TokenTree<'src> {
393 let mut acc = lhs;
394 let mut current = rhs;
395 loop {
396 current = match current {
397 TokenTree::Cons(Op::Field, mut nodes) if nodes.len() == 2 => {
398 let next = nodes.remove(0);
399 let rest = nodes.remove(0);
400 acc = TokenTree::Cons(Op::Field, vec![acc, next]);
401 rest
402 }
403 other => return TokenTree::Cons(Op::Field, vec![acc, other]),
404 };
405 }
406 }
407
408 fn parse_map(&mut self) -> Result<TokenTree<'src>, SyntaxError> {
409 let mut items = Vec::new();
410 if matches!(
411 self.lexer.peek(),
412 Some(Ok(Token {
413 ty: TokenType::RightBrace,
414 ..
415 }))
416 ) {
417 self.lexer.next();
418 return Ok(TokenTree::Cons(Op::Map, items));
419 }
420 loop {
421 let key = self.parse_expr(0)?;
422 self.lexer.expect(
423 TokenType::Colon,
424 "Expected colon between map key and value",
425 )?;
426 let value = self.parse_expr(0)?;
427 items.push(key);
428 items.push(value);
429
430 let token = self.lexer.expect_where(
431 |token| {
432 matches!(token.ty, TokenType::Comma | TokenType::RightBrace)
433 },
434 "continuing map",
435 )?;
436
437 if token.ty == TokenType::RightBrace {
438 break;
439 }
440 }
441 Ok(TokenTree::Cons(Op::Map, items))
442 }
443
444 fn parse_list(&mut self) -> Result<TokenTree<'src>, SyntaxError> {
445 let mut items = Vec::new();
446 if matches!(
447 self.lexer.peek(),
448 Some(Ok(Token {
449 ty: TokenType::RightBracket,
450 ..
451 }))
452 ) {
453 self.lexer.next();
454 return Ok(TokenTree::Cons(Op::List, items));
455 }
456 loop {
457 let item = self.parse_expr(0)?;
458 items.push(item);
459 let token = self.lexer.expect_where(
460 |token| {
461 matches!(
462 token.ty,
463 TokenType::Comma | TokenType::RightBracket
464 )
465 },
466 "continuing list",
467 )?;
468
469 if token.ty == TokenType::RightBracket {
470 break;
471 }
472 }
473 Ok(TokenTree::Cons(Op::List, items))
474 }
475
476 fn parse_fn_call_args(
477 &mut self,
478 ) -> Result<Vec<TokenTree<'src>>, SyntaxError> {
479 let mut args = Vec::new();
480
481 if !matches!(
482 self.lexer.peek(),
483 Some(Ok(Token {
484 ty: TokenType::RightParen,
485 ..
486 }))
487 ) {
488 loop {
489 let arg = self.parse_expr(0)?;
490 args.push(arg);
491 let token = self.lexer.expect_where(
492 |token| {
493 matches!(
494 token.ty,
495 TokenType::Comma | TokenType::RightParen
496 )
497 },
498 "continuing argument list",
499 )?;
500
501 if token.ty == TokenType::RightParen {
502 break;
503 }
504 }
505 } else {
506 self.lexer.next();
507 }
508 Ok(args)
509 }
510}
511
512#[derive(Debug, Clone, PartialEq)]
515pub enum Atom<'src> {
516 Bool(bool),
517 Int(i64),
518 Uint(u64),
519 Double(f64),
520 String(Cow<'src, str>),
521 Bytes(Cow<'src, [u8]>),
522 Ident(&'src str),
523 Null,
524}
525
526impl Serialize for Atom<'_> {
527 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
528 where
529 S: serde::Serializer,
530 {
531 match self {
532 Atom::Bool(b) => {
533 let mut s = serializer.serialize_struct("Bool", 2)?;
534 s.serialize_field("kind", "bool")?;
535 s.serialize_field("value", b)?;
536 s.end()
537 }
538 Atom::Int(i) => {
539 let mut s = serializer.serialize_struct("Int", 2)?;
540 s.serialize_field("kind", "int")?;
541 s.serialize_field("value", i)?;
542 s.end()
543 }
544 Atom::Uint(u) => {
545 let mut s = serializer.serialize_struct("Uint", 2)?;
546 s.serialize_field("kind", "uint")?;
547 s.serialize_field("value", u)?;
548 s.end()
549 }
550 Atom::Double(d) => {
551 let mut s = serializer.serialize_struct("Double", 2)?;
552 s.serialize_field("kind", "double")?;
553 s.serialize_field("value", d)?;
554 s.end()
555 }
556 Atom::String(s) => {
557 let mut srl = serializer.serialize_struct("String", 2)?;
558 srl.serialize_field("kind", "string")?;
559 srl.serialize_field("value", s)?;
560 srl.end()
561 }
562 Atom::Bytes(b) => {
563 let mut srl = serializer.serialize_struct("Bytes", 2)?;
564 srl.serialize_field("kind", "bytes")?;
565 srl.serialize_field("value", b)?;
566 srl.end()
567 }
568 Atom::Ident(i) => {
569 let mut s = serializer.serialize_struct("Ident", 2)?;
570 s.serialize_field("kind", "ident")?;
571 s.serialize_field("value", i)?;
572 s.end()
573 }
574 Atom::Null => {
575 let mut s = serializer.serialize_struct("Null", 1)?;
576 s.serialize_field("kind", "null")?;
577 s.end()
578 }
579 }
580 }
581}
582
583impl fmt::Display for Atom<'_> {
584 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
585 match self {
586 Atom::Bool(b) => write!(f, "{b:?}"),
587 Atom::Int(i) => write!(f, "{}", i),
588 Atom::Uint(u) => write!(f, "{}", u),
589 Atom::Double(d) => write!(f, "{}", d),
590 Atom::String(s) => write!(f, "{:?}", s),
591 Atom::Bytes(b) => write!(f, "{:?}", b),
592 Atom::Ident(i) => write!(f, "{}", i),
593 Atom::Null => write!(f, "null"),
594 }
595 }
596}
597
598#[derive(Debug, Clone, Copy, PartialEq)]
600pub enum Op {
601 Minus,
602 Plus,
603 Multiply,
604 Devide,
605 Mod,
606 NotEqual,
607 EqualEqual,
608 Less,
609 LessEqual,
610 Greater,
611 GreaterEqual,
612 Not,
613 And,
614 Or,
615 IfTernary,
616 In,
617 Call,
618 Index,
619 For,
620 Field,
621 While,
622 Var,
623 Group,
624 Map,
625 List,
626 Dyn,
627}
628
629impl Serialize for Op {
630 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
631 where
632 S: serde::Serializer,
633 {
634 let mut s = serializer.serialize_struct("Op", 1)?;
635 s.serialize_field("op", &self.to_string())?;
636 s.end()
637 }
638}
639
640impl fmt::Display for Op {
641 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
642 let s = match self {
643 Op::IfTernary => "?:",
644 Op::Minus => "-",
645 Op::Plus => "+",
646 Op::Multiply => "*",
647 Op::NotEqual => "!=",
648 Op::EqualEqual => "==",
649 Op::LessEqual => "<=",
650 Op::GreaterEqual => ">=",
651 Op::Less => "<",
652 Op::Greater => ">",
653 Op::Index => "[]",
654 Op::Var => "var",
655 Op::In => "in",
656 Op::Devide => "/",
657 Op::Not => "!",
658 Op::And => "&&",
659 Op::Or => "||",
660 Op::Call => "(args)",
661 Op::For => "for",
662 Op::Field => ".",
663 Op::While => "while",
664 Op::Group => "(",
665 Op::Map => "{map}",
666 Op::List => "[list]",
667 Op::Mod => "%",
668 Op::Dyn => "dyn",
669 };
670 write!(f, "{}", s)
671 }
672}
673
674#[derive(Debug, Clone, PartialEq)]
676pub enum TokenTree<'src> {
677 Atom(Atom<'src>),
678 Cons(Op, Vec<TokenTree<'src>>),
679 Call {
680 func: Box<TokenTree<'src>>,
681 args: Vec<TokenTree<'src>>,
682 is_method: bool,
683 },
684}
685
686impl Serialize for TokenTree<'_> {
687 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
688 where
689 S: serde::Serializer,
690 {
691 match self {
692 TokenTree::Atom(atom) => atom.serialize(serializer),
693 TokenTree::Cons(op, args) => {
694 let mut state = serializer.serialize_struct("Cons", 2)?;
695 state.serialize_field("op", op)?;
696 state.serialize_field("args", args)?;
697 state.end()
698 }
699 TokenTree::Call {
700 func,
701 args,
702 is_method,
703 } => {
704 let mut state = serializer.serialize_struct("Call", 3)?;
705 state.serialize_field("func", func)?;
706 state.serialize_field("args", args)?;
707 state.serialize_field("is_method", is_method)?;
708 state.end()
709 }
710 }
711 }
712}
713
714impl fmt::Display for TokenTree<'_> {
715 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
716 match self {
717 TokenTree::Atom(atom) => write!(f, "{}", atom),
718 TokenTree::Cons(op, args) => {
719 write!(f, "{}", op)?;
720 for arg in args {
721 write!(f, " {}", arg)?;
722 }
723 Ok(())
724 }
725 TokenTree::Call {
726 func,
727 args,
728 is_method,
729 } => {
730 if *is_method {
731 write!(
732 f,
733 "{}.{}({})",
734 args[0],
735 func,
736 args[1..]
737 .iter()
738 .map(|arg| arg.to_string())
739 .collect::<Vec<_>>()
740 .join(", ")
741 )
742 } else {
743 write!(
744 f,
745 "{}({})",
746 func,
747 args.iter()
748 .map(|arg| arg.to_string())
749 .collect::<Vec<_>>()
750 .join(", ")
751 )
752 }
753 }
754 }
755 }
756}
757
758fn prefix_binding_power(op: Op) -> ((), u8) {
759 match op {
760 Op::Minus | Op::Not => ((), 13),
761 _ => panic!("Unexpected operator: {:?}", op),
762 }
763}
764
765fn postfix_binding_power(op: Op) -> Option<(u8, ())> {
766 match op {
767 Op::Index => Some((15, ())),
768 Op::Call => Some((17, ())),
769 _ => None,
770 }
771}
772
773fn infix_binding_power(op: Op) -> Option<(u8, u8)> {
786 let res = match op {
787 Op::IfTernary => (2, 1),
789 Op::Or => (3, 4),
790 Op::And => (5, 6),
791 Op::In
792 | Op::NotEqual
793 | Op::EqualEqual
794 | Op::Less
795 | Op::LessEqual
796 | Op::Greater
797 | Op::GreaterEqual => (7, 8),
798 Op::Plus | Op::Minus => (9, 10),
799 Op::Multiply | Op::Devide | Op::Mod => (11, 12),
800 Op::Field | Op::Call => (18, 17),
801 _ => return None,
802 };
803 Some(res)
804}
805
806#[cfg(test)]
807mod tests {
808 use super::*;
809 use miette::Report;
810
811 #[track_caller]
812 fn assert_span_matches(
813 err: &SyntaxError,
814 expected_offset: usize,
815 expected_slice: &str,
816 report: &Report,
817 ) {
818 let span = err.span();
819 let offset: usize = span.offset();
820 assert_eq!(
821 offset, expected_offset,
822 "unexpected span offset: {report:?}"
823 );
824 assert_eq!(
825 span.len(),
826 expected_slice.len(),
827 "unexpected span len: {report:?}"
828 );
829 let fragment = &err.source_text()[offset..offset + span.len()];
830 assert_eq!(
831 fragment, expected_slice,
832 "unexpected source slice: {report:?}"
833 );
834 }
835
836 #[test]
837 fn test_add_and_multiply() {
838 let input = "1 + 2 * 3";
839 let mut parser = Parser::new(input);
840 let tree = parser.parse().unwrap();
841 assert_eq!(
842 tree,
843 TokenTree::Cons(
844 Op::Plus,
845 vec![
846 TokenTree::Atom(Atom::Int(1)),
847 TokenTree::Cons(
848 Op::Multiply,
849 vec![
850 TokenTree::Atom(Atom::Int(2)),
851 TokenTree::Atom(Atom::Int(3)),
852 ]
853 )
854 ]
855 )
856 );
857 }
858
859 #[test]
860 fn test_field_access() {
861 let input = "foo.bar.baz";
862 let mut parser = Parser::new(input);
863 let tree = parser.parse().unwrap();
864 assert_eq!(
865 tree,
866 TokenTree::Cons(
867 Op::Field,
868 vec![
869 TokenTree::Cons(
870 Op::Field,
871 vec![
872 TokenTree::Atom(Atom::Ident("foo")),
873 TokenTree::Atom(Atom::Ident("bar")),
874 ]
875 ),
876 TokenTree::Atom(Atom::Ident("baz")),
877 ]
878 )
879 );
880
881 let input = "foo.check[0].baz";
882 let mut parser = Parser::new(input);
883 let tree = parser.parse().unwrap();
884 assert_eq!(
885 tree,
886 TokenTree::Cons(
887 Op::Field,
888 vec![
889 TokenTree::Cons(
890 Op::Index,
891 vec![
892 TokenTree::Cons(
893 Op::Field,
894 vec![
895 TokenTree::Atom(Atom::Ident("foo")),
896 TokenTree::Atom(Atom::Ident("check")),
897 ],
898 ),
899 TokenTree::Atom(Atom::Int(0)),
900 ],
901 ),
902 TokenTree::Atom(Atom::Ident("baz")),
903 ]
904 )
905 );
906 }
907
908 #[test]
909 fn test_function_call() {
910 let input = "foo(bar, baz)";
911 let mut parser = Parser::new(input);
912 let tree = parser.parse().unwrap();
913 assert_eq!(
914 tree,
915 TokenTree::Call {
916 func: Box::new(TokenTree::Atom(Atom::Ident("foo"))),
917 args: vec![
918 TokenTree::Atom(Atom::Ident("bar")),
919 TokenTree::Atom(Atom::Ident("baz")),
920 ],
921 is_method: false,
922 }
923 );
924
925 let input = "foo([])";
926 let mut parser = Parser::new(input);
927 let tree = parser.parse().unwrap();
928 assert_eq!(
929 tree,
930 TokenTree::Call {
931 func: Box::new(TokenTree::Atom(Atom::Ident("foo"))),
932 args: vec![TokenTree::Cons(Op::List, vec![])],
933 is_method: false,
934 }
935 );
936
937 let input = "foo({})";
938 let mut parser = Parser::new(input);
939 let tree = parser.parse().unwrap();
940 assert_eq!(
941 tree,
942 TokenTree::Call {
943 func: Box::new(TokenTree::Atom(Atom::Ident("foo"))),
944 args: vec![TokenTree::Cons(Op::Map, vec![])],
945 is_method: false,
946 }
947 );
948 }
949
950 #[test]
951 fn test_method_call() {
952 let input = "foo.bar(baz)";
953 let mut parser = Parser::new(input);
954 let tree = parser.parse().unwrap();
955 assert_eq!(
956 tree,
957 TokenTree::Call {
958 func: Box::new(TokenTree::Atom(Atom::Ident("bar"))),
959 args: vec![
960 TokenTree::Atom(Atom::Ident("foo")),
961 TokenTree::Atom(Atom::Ident("baz")),
962 ],
963 is_method: true,
964 }
965 );
966 }
967
968 #[test]
969 fn test_method_call_chain() {
970 let input = "foo.bar().baz()";
971 let mut parser = Parser::new(input);
972 let tree = parser.parse().unwrap();
973 let want = TokenTree::Call {
974 func: Box::new(TokenTree::Atom(Atom::Ident("baz"))),
975 args: vec![TokenTree::Call {
976 func: Box::new(TokenTree::Atom(Atom::Ident("bar"))),
977 args: vec![TokenTree::Atom(Atom::Ident("foo"))],
978 is_method: true,
979 }],
980 is_method: true,
981 };
982 assert_eq!(tree, want);
983 }
984
985 #[test]
986 fn test_long_method_chain() {
987 let input = "foo.bar().baz().qux()";
988 let mut parser = Parser::new(input);
989 let tree = parser.parse().unwrap();
990 let want = TokenTree::Call {
991 func: Box::new(TokenTree::Atom(Atom::Ident("qux"))),
992 args: vec![TokenTree::Call {
993 func: Box::new(TokenTree::Atom(Atom::Ident("baz"))),
994 args: vec![TokenTree::Call {
995 func: Box::new(TokenTree::Atom(Atom::Ident("bar"))),
996 args: vec![TokenTree::Atom(Atom::Ident("foo"))],
997 is_method: true,
998 }],
999 is_method: true,
1000 }],
1001 is_method: true,
1002 };
1003 assert_eq!(tree, want);
1004 }
1005
1006 #[test]
1007 fn test_nested_method_call() {
1008 let input = "foo.all(test, test.size() > 4)";
1009 let mut parser = Parser::new(input);
1010 let tree = parser.parse().unwrap();
1011 let want = TokenTree::Call {
1012 func: Box::new(TokenTree::Atom(Atom::Ident("all"))),
1013 args: vec![
1014 TokenTree::Atom(Atom::Ident("foo")),
1015 TokenTree::Atom(Atom::Ident("test")),
1016 TokenTree::Cons(
1017 Op::Greater,
1018 vec![
1019 TokenTree::Call {
1020 func: Box::new(TokenTree::Atom(Atom::Ident(
1021 "size",
1022 ))),
1023 args: vec![TokenTree::Atom(Atom::Ident("test"))],
1024 is_method: true,
1025 },
1026 TokenTree::Atom(Atom::Int(4)),
1027 ],
1028 ),
1029 ],
1030 is_method: true,
1031 };
1032 assert_eq!(tree, want, "expected {want:?}, got {tree:?}");
1033 }
1034
1035 #[test]
1036 fn test_list_definition() {
1037 let input = "[1, 2, 3]";
1038 let mut parser = Parser::new(input);
1039 let tree = parser.parse();
1040 assert!(tree.is_ok(), "{:?}", tree);
1041 let tree = tree.unwrap();
1042 assert_eq!(
1043 tree,
1044 TokenTree::Cons(
1045 Op::List,
1046 vec![
1047 TokenTree::Atom(Atom::Int(1)),
1048 TokenTree::Atom(Atom::Int(2)),
1049 TokenTree::Atom(Atom::Int(3)),
1050 ]
1051 )
1052 );
1053
1054 let input = "[]";
1055 let mut parser = Parser::new(input);
1056 let tree = parser.parse().unwrap();
1057 assert_eq!(tree, TokenTree::Cons(Op::List, vec![]));
1058 }
1059
1060 #[test]
1061 fn test_map_definition() {
1062 let input = "{foo: 1, bar: 2}";
1063 let mut parser = Parser::new(input);
1064 let tree = parser.parse();
1065 assert!(tree.is_ok(), "{:?}", tree);
1066 let tree = tree.unwrap();
1067 assert_eq!(
1068 tree,
1069 TokenTree::Cons(
1070 Op::Map,
1071 vec![
1072 TokenTree::Atom(Atom::Ident("foo")),
1073 TokenTree::Atom(Atom::Int(1)),
1074 TokenTree::Atom(Atom::Ident("bar")),
1075 TokenTree::Atom(Atom::Int(2)),
1076 ]
1077 )
1078 );
1079
1080 let input = "{}";
1081 let mut parser = Parser::new(input);
1082 let tree = parser.parse().unwrap();
1083 assert_eq!(tree, TokenTree::Cons(Op::Map, vec![]));
1084 }
1085
1086 #[test]
1087 fn test_grouping() {
1088 let input = "(1 + 2) * 3 % 4";
1089 let mut parser = Parser::new(input);
1090 let tree = parser.parse().unwrap();
1091 assert_eq!(
1092 tree,
1093 TokenTree::Cons(
1094 Op::Mod,
1095 vec![
1096 TokenTree::Cons(
1097 Op::Multiply,
1098 vec![
1099 TokenTree::Cons(
1100 Op::Group,
1101 vec![TokenTree::Cons(
1102 Op::Plus,
1103 vec![
1104 TokenTree::Atom(Atom::Int(1)),
1105 TokenTree::Atom(Atom::Int(2)),
1106 ]
1107 ),]
1108 ),
1109 TokenTree::Atom(Atom::Int(3)),
1110 ]
1111 ),
1112 TokenTree::Atom(Atom::Int(4)),
1113 ]
1114 )
1115 );
1116 }
1117
1118 #[test]
1119 fn test_unary_minus() {
1120 let input = "-1";
1121 let mut parser = Parser::new(input);
1122 let tree = parser.parse().unwrap();
1123 assert_eq!(
1124 tree,
1125 TokenTree::Cons(Op::Minus, vec![TokenTree::Atom(Atom::Int(1))])
1126 );
1127 }
1128
1129 #[test]
1130 fn test_unary_not() {
1131 let input = "!true";
1132 let mut parser = Parser::new(input);
1133 let tree = parser.parse().unwrap();
1134 assert_eq!(
1135 tree,
1136 TokenTree::Cons(Op::Not, vec![TokenTree::Atom(Atom::Bool(true))])
1137 );
1138 }
1139
1140 #[test]
1141 fn test_relations() {
1142 let input = "1 < 2 && 3 >= 4 || 5 == 6 && 5 in 6";
1143 let mut parser = Parser::new(input);
1144 let tree = parser.parse().unwrap();
1145 assert_eq!(
1146 tree,
1147 TokenTree::Cons(
1148 Op::Or,
1149 vec![
1150 TokenTree::Cons(
1151 Op::And,
1152 vec![
1153 TokenTree::Cons(
1154 Op::Less,
1155 vec![
1156 TokenTree::Atom(Atom::Int(1)),
1157 TokenTree::Atom(Atom::Int(2)),
1158 ]
1159 ),
1160 TokenTree::Cons(
1161 Op::GreaterEqual,
1162 vec![
1163 TokenTree::Atom(Atom::Int(3)),
1164 TokenTree::Atom(Atom::Int(4)),
1165 ]
1166 ),
1167 ]
1168 ),
1169 TokenTree::Cons(
1170 Op::And,
1171 vec![
1172 TokenTree::Cons(
1173 Op::EqualEqual,
1174 vec![
1175 TokenTree::Atom(Atom::Int(5)),
1176 TokenTree::Atom(Atom::Int(6)),
1177 ]
1178 ),
1179 TokenTree::Cons(
1180 Op::In,
1181 vec![
1182 TokenTree::Atom(Atom::Int(5)),
1183 TokenTree::Atom(Atom::Int(6)),
1184 ]
1185 ),
1186 ]
1187 ),
1188 ]
1189 )
1190 );
1191 }
1192
1193 #[test]
1194 fn test_singuler_expression() {
1195 let tt = vec![
1196 ("identifier", TokenTree::Atom(Atom::Ident("identifier"))),
1197 ("123", TokenTree::Atom(Atom::Int(123))),
1198 ("123u", TokenTree::Atom(Atom::Uint(123))),
1199 ("123.456", TokenTree::Atom(Atom::Double(123.456))),
1200 ("true", TokenTree::Atom(Atom::Bool(true))),
1201 ("false", TokenTree::Atom(Atom::Bool(false))),
1202 (
1203 "\"string\"",
1204 TokenTree::Atom(Atom::String(Cow::Borrowed("string"))),
1205 ),
1206 ("null", TokenTree::Atom(Atom::Null)),
1207 ]
1208 .into_iter();
1209
1210 for (input, expected) in tt {
1211 let mut parser = Parser::new(input);
1212 let tree = parser.parse();
1213 assert!(tree.is_ok(), "input={:?}, out={:?}", input, tree);
1214 let tree = tree.unwrap();
1215 assert_eq!(tree, expected);
1216 }
1217 }
1218
1219 #[test]
1220 fn test_indexing() {
1221 let input = "foo[1]";
1222 let mut parser = Parser::new(input);
1223 let tree = parser.parse().unwrap();
1224 assert_eq!(
1225 tree,
1226 TokenTree::Cons(
1227 Op::Index,
1228 vec![
1229 TokenTree::Atom(Atom::Ident("foo")),
1230 TokenTree::Atom(Atom::Int(1)),
1231 ]
1232 )
1233 );
1234
1235 let input = "foo[1][2]";
1236 let mut parser = Parser::new(input);
1237 let tree = parser.parse().unwrap();
1238 assert_eq!(
1239 tree,
1240 TokenTree::Cons(
1241 Op::Index,
1242 vec![
1243 TokenTree::Cons(
1244 Op::Index,
1245 vec![
1246 TokenTree::Atom(Atom::Ident("foo")),
1247 TokenTree::Atom(Atom::Int(1)),
1248 ]
1249 ),
1250 TokenTree::Atom(Atom::Int(2)),
1251 ]
1252 )
1253 );
1254 }
1255
1256 #[test]
1257 fn test_ternary_if() {
1258 let input = "true ? 1 : 2";
1259 let mut parser = Parser::new(input);
1260 let tree = parser.parse().unwrap();
1261 assert_eq!(
1262 tree,
1263 TokenTree::Cons(
1264 Op::IfTernary,
1265 vec![
1266 TokenTree::Atom(Atom::Bool(true)),
1267 TokenTree::Atom(Atom::Int(1)),
1268 TokenTree::Atom(Atom::Int(2)),
1269 ]
1270 )
1271 );
1272
1273 let input = "true ? 1 : false ? 2 : 3";
1274 let mut parser = Parser::new(input);
1275 let tree = parser.parse().unwrap();
1276 assert_eq!(
1277 tree,
1278 TokenTree::Cons(
1279 Op::IfTernary,
1280 vec![
1281 TokenTree::Atom(Atom::Bool(true)),
1282 TokenTree::Atom(Atom::Int(1)),
1283 TokenTree::Cons(
1284 Op::IfTernary,
1285 vec![
1286 TokenTree::Atom(Atom::Bool(false)),
1287 TokenTree::Atom(Atom::Int(2)),
1288 TokenTree::Atom(Atom::Int(3)),
1289 ]
1290 ),
1291 ]
1292 )
1293 );
1294 }
1295
1296 #[test]
1297 fn test_method_relation() {
1298 let input = "foo.bar() < 4";
1299 let mut parser = Parser::new(input);
1300 let tree = parser.parse().unwrap();
1301 assert_eq!(
1302 tree,
1303 TokenTree::Cons(
1304 Op::Less,
1305 vec![
1306 TokenTree::Call {
1307 func: Box::new(TokenTree::Atom(Atom::Ident("bar"))),
1308 args: vec![TokenTree::Atom(Atom::Ident("foo"))],
1309 is_method: true,
1310 },
1311 TokenTree::Atom(Atom::Int(4)),
1312 ]
1313 )
1314 );
1315 }
1316
1317 #[test]
1318 fn test_inline_function_call() {
1319 let input = "1 + size(2u)";
1320 let mut parser = Parser::new(input);
1321 let tree = parser.parse().unwrap();
1322 assert_eq!(
1323 tree,
1324 TokenTree::Cons(
1325 Op::Plus,
1326 vec![
1327 TokenTree::Atom(Atom::Int(1)),
1328 TokenTree::Call {
1329 func: Box::new(TokenTree::Atom(Atom::Ident("size"))),
1330 args: vec![TokenTree::Atom(Atom::Uint(2))],
1331 is_method: false,
1332 },
1333 ]
1334 )
1335 );
1336 }
1337
1338 #[test]
1339 fn test_inline_dyn_call() {
1340 let input = "1 + dyn(2u)";
1341 let mut parser = Parser::new(input);
1342 let tree = parser.parse().unwrap();
1343 assert_eq!(
1344 tree,
1345 TokenTree::Cons(
1346 Op::Plus,
1347 vec![
1348 TokenTree::Atom(Atom::Int(1)),
1349 TokenTree::Cons(
1350 Op::Dyn,
1351 vec![TokenTree::Atom(Atom::Uint(2))],
1352 ),
1353 ]
1354 )
1355 );
1356 }
1357
1358 #[test]
1359 fn test_nested_list_with_map() {
1360 let input = "[{foo: 1}, {bar: 2}]";
1361 let mut parser = Parser::new(input);
1362 let tree = parser.parse().unwrap();
1363 assert_eq!(
1364 tree,
1365 TokenTree::Cons(
1366 Op::List,
1367 vec![
1368 TokenTree::Cons(
1369 Op::Map,
1370 vec![
1371 TokenTree::Atom(Atom::Ident("foo")),
1372 TokenTree::Atom(Atom::Int(1)),
1373 ]
1374 ),
1375 TokenTree::Cons(
1376 Op::Map,
1377 vec![
1378 TokenTree::Atom(Atom::Ident("bar")),
1379 TokenTree::Atom(Atom::Int(2)),
1380 ]
1381 ),
1382 ]
1383 )
1384 );
1385 }
1386
1387 #[test]
1388 fn test_method_call_with_indexing() {
1389 let input = "foo.bar(x, t[x] > 10)";
1390 let mut parser = Parser::new(input);
1391 let tree = parser.parse().unwrap();
1392
1393 let want = TokenTree::Call {
1394 func: Box::new(TokenTree::Atom(Atom::Ident("bar"))),
1395 args: vec![
1396 TokenTree::Atom(Atom::Ident("foo")),
1397 TokenTree::Atom(Atom::Ident("x")),
1398 TokenTree::Cons(
1399 Op::Greater,
1400 vec![
1401 TokenTree::Cons(
1402 Op::Index,
1403 vec![
1404 TokenTree::Atom(Atom::Ident("t")),
1405 TokenTree::Atom(Atom::Ident("x")),
1406 ],
1407 ),
1408 TokenTree::Atom(Atom::Int(10)),
1409 ],
1410 ),
1411 ],
1412 is_method: true,
1413 };
1414
1415 assert_eq!(tree, want);
1416 }
1417
1418 #[test]
1419 fn test_nested_fields() {
1420 let input = "foo.bar.baz";
1421 let mut parser = Parser::new(input);
1422 let tree = parser.parse().unwrap();
1423
1424 let want = TokenTree::Cons(
1425 Op::Field,
1426 vec![
1427 TokenTree::Cons(
1428 Op::Field,
1429 vec![
1430 TokenTree::Atom(Atom::Ident("foo")),
1431 TokenTree::Atom(Atom::Ident("bar")),
1432 ],
1433 ),
1434 TokenTree::Atom(Atom::Ident("baz")),
1435 ],
1436 );
1437
1438 assert_eq!(tree, want);
1439 }
1440
1441 #[test]
1442 fn test_nested_fields_method_call() {
1443 let input = "foo.bar.foo.baz()";
1444 let mut parser = Parser::new(input);
1445 let tree = parser.parse().unwrap();
1446
1447 let want = TokenTree::Call {
1448 func: Box::new(TokenTree::Atom(Atom::Ident("baz"))),
1449 args: vec![TokenTree::Cons(
1450 Op::Field,
1451 vec![
1452 TokenTree::Cons(
1453 Op::Field,
1454 vec![
1455 TokenTree::Atom(Atom::Ident("foo")),
1456 TokenTree::Atom(Atom::Ident("bar")),
1457 ],
1458 ),
1459 TokenTree::Atom(Atom::Ident("foo")),
1460 ],
1461 )],
1462 is_method: true,
1463 };
1464
1465 assert_eq!(tree, want);
1466 }
1467
1468 #[test]
1469 fn test_nested_method_call_with_indexing() {
1470 let input = "foo.bar.filter(x, x > 10)[0].id";
1471 let mut parser = Parser::new(input);
1472 let tree = parser.parse().unwrap();
1473
1474 let want = TokenTree::Cons(
1475 Op::Field,
1476 vec![
1477 TokenTree::Cons(
1478 Op::Index,
1479 vec![
1480 TokenTree::Call {
1481 func: Box::new(TokenTree::Atom(Atom::Ident(
1482 "filter",
1483 ))),
1484 args: vec![
1485 TokenTree::Cons(
1486 Op::Field,
1487 vec![
1488 TokenTree::Atom(Atom::Ident("foo")),
1489 TokenTree::Atom(Atom::Ident("bar")),
1490 ],
1491 ),
1492 TokenTree::Atom(Atom::Ident("x")),
1493 TokenTree::Cons(
1494 Op::Greater,
1495 vec![
1496 TokenTree::Atom(Atom::Ident("x")),
1497 TokenTree::Atom(Atom::Int(10)),
1498 ],
1499 ),
1500 ],
1501 is_method: true,
1502 },
1503 TokenTree::Atom(Atom::Int(0)),
1504 ],
1505 ),
1506 TokenTree::Atom(Atom::Ident("id")),
1507 ],
1508 );
1509
1510 assert_eq!(tree, want);
1511 }
1512
1513 #[test]
1514 fn test_parser_propagates_lexer_error_span() {
1515 let input = "&";
1516 let mut parser = Parser::new(input);
1517 let err = parser.parse().expect_err("expected lexer error");
1518 let report = Report::new(err.clone());
1519 assert_span_matches(&err, 0, "&", &report);
1520 assert!(
1521 err.message().contains("Unexpected character"),
1522 "unexpected message: {}; {report:?}",
1523 err.message()
1524 );
1525 }
1526
1527 #[test]
1528 fn test_parser_propagates_eof_span() {
1529 let input = "(";
1530 let mut parser = Parser::new(input);
1531 let err = parser.parse().expect_err("expected missing closing paren");
1532 let span = err.span();
1533 let offset: usize = span.offset();
1534 assert_eq!(
1535 offset,
1536 input.len(),
1537 "eof span should point to end of input"
1538 );
1539 assert_eq!(span.len(), 0, "eof span should have zero length");
1540 }
1541
1542 #[test]
1543 fn test_parser_propagates_unexpected_token_span() {
1544 let input = "1 + (1abc";
1545 let mut parser = Parser::new(input);
1546 let err = parser
1547 .parse()
1548 .expect_err("expected missing closing paren error");
1549 let report = Report::new(err.clone());
1550 assert_span_matches(&err, "1 + (1".len(), "abc", &report);
1551 assert!(
1552 err.message().contains("Unexpected token"),
1553 "unexpected message: {}; {report:?}",
1554 err.message()
1555 );
1556 }
1557}