1mod expr;
2mod interpolation;
3pub mod lexer;
4mod stmt;
5
6use chumsky::{prelude::*, Stream};
7use error::convert_lexer_error;
8use error::convert_parser_error;
9pub use error::Error;
10
11use self::lexer::Token;
12
13use prql_ast::stmt::*;
14use prql_ast::Span;
15
16mod error;
17mod span;
18
19use span::ParserSpan;
20
21use common::PError;
22
23pub fn parse_source(source: &str, source_id: u16) -> Result<Vec<Stmt>, Vec<Error>> {
25 let mut errors = Vec::new();
26
27 let (tokens, lex_errors) = ::chumsky::Parser::parse_recovery(&lexer::lexer(), source);
28
29 errors.extend(
30 lex_errors
31 .into_iter()
32 .map(|err| convert_lexer_error(source, err, source_id)),
33 );
34
35 let ast = if let Some(tokens) = tokens {
36 let stream = prepare_stream(tokens, source, source_id);
37
38 let (ast, parse_errors) = ::chumsky::Parser::parse_recovery(&stmt::source(), stream);
39
40 errors.extend(parse_errors.into_iter().map(convert_parser_error));
41
42 ast
43 } else {
44 None
45 };
46
47 if errors.is_empty() {
48 Ok(ast.unwrap_or_default())
49 } else {
50 Err(errors)
51 }
52}
53
54#[cfg(test)]
56pub fn parse_single(source: &str) -> Result<Vec<Stmt>, Vec<Error>> {
57 parse_source(source, 0)
58}
59
60fn prepare_stream(
61 tokens: Vec<(Token, std::ops::Range<usize>)>,
62 source: &str,
63 source_id: u16,
64) -> Stream<Token, ParserSpan, impl Iterator<Item = (Token, ParserSpan)> + Sized> {
65 let tokens = tokens
66 .into_iter()
67 .map(move |(t, s)| (t, ParserSpan::new(source_id, s)));
68 let len = source.chars().count();
69 let eoi = ParserSpan(Span {
70 start: len,
71 end: len + 1,
72 source_id,
73 });
74 Stream::from_iter(eoi, tokens)
75}
76
77mod common {
78 use chumsky::prelude::*;
79
80 use super::{lexer::Token, span::ParserSpan};
81 use prql_ast::expr::*;
82 use prql_ast::stmt::*;
83
84 pub type PError = Simple<Token, ParserSpan>;
85
86 pub fn ident_part() -> impl Parser<Token, String, Error = PError> {
87 select! { Token::Ident(ident) => ident }.map_err(|e: PError| {
88 Simple::expected_input_found(
89 e.span(),
90 [Some(Token::Ident("".to_string()))],
91 e.found().cloned(),
92 )
93 })
94 }
95
96 pub fn keyword(kw: &'static str) -> impl Parser<Token, (), Error = PError> + Clone {
97 just(Token::Keyword(kw.to_string())).ignored()
98 }
99
100 pub fn new_line() -> impl Parser<Token, (), Error = PError> + Clone {
101 just(Token::NewLine).ignored()
102 }
103
104 pub fn ctrl(char: char) -> impl Parser<Token, (), Error = PError> + Clone {
105 just(Token::Control(char)).ignored()
106 }
107
108 pub fn into_stmt((annotations, kind): (Vec<Annotation>, StmtKind), span: ParserSpan) -> Stmt {
109 Stmt {
110 kind,
111 span: Some(span.0),
112 annotations,
113 }
114 }
115
116 pub fn into_expr(kind: ExprKind, span: ParserSpan) -> Expr {
117 Expr {
118 span: Some(span.0),
119 ..Expr::new(kind)
120 }
121 }
122}
123
124#[cfg(test)]
125mod test {
126
127 use super::*;
128 use insta::assert_yaml_snapshot;
129 use prql_ast::expr::{Expr, FuncCall};
130
131 fn parse_expr(source: &str) -> Result<Expr, Vec<Error>> {
132 let tokens = Parser::parse(&lexer::lexer(), source).map_err(|errs| {
133 errs.into_iter()
134 .map(|err| convert_lexer_error(source, err, 0))
135 .collect::<Vec<_>>()
136 })?;
137
138 let stream = prepare_stream(tokens, source, 0);
139 Parser::parse(&expr::expr_call().then_ignore(end()), stream)
140 .map_err(|errs| errs.into_iter().map(convert_parser_error).collect())
141 }
142
143 #[test]
144 fn test_pipeline_parse_tree() {
145 assert_yaml_snapshot!(parse_single(
146 r#"
147from employees
148filter country == "USA" # Each line transforms the previous result.
149derive { # This adds columns / variables.
150 gross_salary = salary + payroll_tax,
151 gross_cost = gross_salary + benefits_cost # Variables can use other variables.
152}
153filter gross_cost > 0
154group {title, country} ( # For each group use a nested pipeline
155 aggregate { # Aggregate each group to a single row
156 average salary,
157 average gross_salary,
158 sum salary,
159 sum gross_salary,
160 average gross_cost,
161 sum_gross_cost = sum gross_cost,
162 ct = count salary,
163 }
164)
165sort sum_gross_cost
166filter ct > 200
167take 20
168 "#
169 )
170 .unwrap());
171 }
172
173 #[test]
174 fn test_take() {
175 parse_single("take 10").unwrap();
176
177 assert_yaml_snapshot!(parse_single(r#"take 10"#).unwrap(), @r###"
178 ---
179 - Main:
180 FuncCall:
181 name:
182 Ident:
183 - take
184 args:
185 - Literal:
186 Integer: 10
187 annotations: []
188 "###);
189
190 assert_yaml_snapshot!(parse_single(r#"take ..10"#).unwrap(), @r###"
191 ---
192 - Main:
193 FuncCall:
194 name:
195 Ident:
196 - take
197 args:
198 - Range:
199 start: ~
200 end:
201 Literal:
202 Integer: 10
203 annotations: []
204 "###);
205
206 assert_yaml_snapshot!(parse_single(r#"take 1..10"#).unwrap(), @r###"
207 ---
208 - Main:
209 FuncCall:
210 name:
211 Ident:
212 - take
213 args:
214 - Range:
215 start:
216 Literal:
217 Integer: 1
218 end:
219 Literal:
220 Integer: 10
221 annotations: []
222 "###);
223 }
224
225 #[test]
226 fn test_ranges() {
227 assert_yaml_snapshot!(parse_expr(r#"3..5"#).unwrap(), @r###"
228 ---
229 Range:
230 start:
231 Literal:
232 Integer: 3
233 end:
234 Literal:
235 Integer: 5
236 "###);
237
238 assert_yaml_snapshot!(parse_expr(r#"-2..-5"#).unwrap(), @r###"
239 ---
240 Range:
241 start:
242 Unary:
243 op: Neg
244 expr:
245 Literal:
246 Integer: 2
247 end:
248 Unary:
249 op: Neg
250 expr:
251 Literal:
252 Integer: 5
253 "###);
254
255 assert_yaml_snapshot!(parse_expr(r#"(-2..(-5 | abs))"#).unwrap(), @r###"
256 ---
257 Range:
258 start:
259 Unary:
260 op: Neg
261 expr:
262 Literal:
263 Integer: 2
264 end:
265 Pipeline:
266 exprs:
267 - Unary:
268 op: Neg
269 expr:
270 Literal:
271 Integer: 5
272 - Ident:
273 - abs
274 "###);
275
276 assert_yaml_snapshot!(parse_expr(r#"(2 + 5)..'a'"#).unwrap(), @r###"
277 ---
278 Range:
279 start:
280 Binary:
281 left:
282 Literal:
283 Integer: 2
284 op: Add
285 right:
286 Literal:
287 Integer: 5
288 end:
289 Literal:
290 String: a
291 "###);
292
293 assert_yaml_snapshot!(parse_expr(r#"1.6..rel.col"#).unwrap(), @r###"
294 ---
295 Range:
296 start:
297 Literal:
298 Float: 1.6
299 end:
300 Ident:
301 - rel
302 - col
303 "###);
304
305 assert_yaml_snapshot!(parse_expr(r#"6.."#).unwrap(), @r###"
306 ---
307 Range:
308 start:
309 Literal:
310 Integer: 6
311 end: ~
312 "###);
313 assert_yaml_snapshot!(parse_expr(r#"..7"#).unwrap(), @r###"
314 ---
315 Range:
316 start: ~
317 end:
318 Literal:
319 Integer: 7
320 "###);
321
322 assert_yaml_snapshot!(parse_expr(r#".."#).unwrap(), @r###"
323 ---
324 Range:
325 start: ~
326 end: ~
327 "###);
328
329 assert_yaml_snapshot!(parse_expr(r#"@2020-01-01..@2021-01-01"#).unwrap(), @r###"
330 ---
331 Range:
332 start:
333 Literal:
334 Date: 2020-01-01
335 end:
336 Literal:
337 Date: 2021-01-01
338 "###);
339 }
340
341 #[test]
342 fn test_basic_exprs() {
343 assert_yaml_snapshot!(parse_expr(r#"country == "USA""#).unwrap(), @r###"
344 ---
345 Binary:
346 left:
347 Ident:
348 - country
349 op: Eq
350 right:
351 Literal:
352 String: USA
353 "###);
354 assert_yaml_snapshot!(parse_expr("select {a, b, c}").unwrap(), @r###"
355 ---
356 FuncCall:
357 name:
358 Ident:
359 - select
360 args:
361 - Tuple:
362 - Ident:
363 - a
364 - Ident:
365 - b
366 - Ident:
367 - c
368 "###);
369 assert_yaml_snapshot!(parse_expr(
370 "group {title, country} (
371 aggregate {sum salary}
372 )"
373 ).unwrap(), @r###"
374 ---
375 FuncCall:
376 name:
377 Ident:
378 - group
379 args:
380 - Tuple:
381 - Ident:
382 - title
383 - Ident:
384 - country
385 - FuncCall:
386 name:
387 Ident:
388 - aggregate
389 args:
390 - Tuple:
391 - FuncCall:
392 name:
393 Ident:
394 - sum
395 args:
396 - Ident:
397 - salary
398 "###);
399 assert_yaml_snapshot!(parse_expr(
400 r#" filter country == "USA""#
401 ).unwrap(), @r###"
402 ---
403 FuncCall:
404 name:
405 Ident:
406 - filter
407 args:
408 - Binary:
409 left:
410 Ident:
411 - country
412 op: Eq
413 right:
414 Literal:
415 String: USA
416 "###);
417 assert_yaml_snapshot!(parse_expr("{a, b, c,}").unwrap(), @r###"
418 ---
419 Tuple:
420 - Ident:
421 - a
422 - Ident:
423 - b
424 - Ident:
425 - c
426 "###);
427 assert_yaml_snapshot!(parse_expr(
428 r#"{
429 gross_salary = salary + payroll_tax,
430 gross_cost = gross_salary + benefits_cost
431}"#
432 ).unwrap(), @r###"
433 ---
434 Tuple:
435 - Binary:
436 left:
437 Ident:
438 - salary
439 op: Add
440 right:
441 Ident:
442 - payroll_tax
443 alias: gross_salary
444 - Binary:
445 left:
446 Ident:
447 - gross_salary
448 op: Add
449 right:
450 Ident:
451 - benefits_cost
452 alias: gross_cost
453 "###);
454 assert_yaml_snapshot!(parse_single(
456 r#"# this is a comment
457 select a"#
458 ).unwrap(), @r###"
459 ---
460 - Main:
461 FuncCall:
462 name:
463 Ident:
464 - select
465 args:
466 - Ident:
467 - a
468 annotations: []
469 "###);
470 assert_yaml_snapshot!(parse_expr(
471 "join side:left country (id==employee_id)"
472 ).unwrap(), @r###"
473 ---
474 FuncCall:
475 name:
476 Ident:
477 - join
478 args:
479 - Ident:
480 - country
481 - Binary:
482 left:
483 Ident:
484 - id
485 op: Eq
486 right:
487 Ident:
488 - employee_id
489 named_args:
490 side:
491 Ident:
492 - left
493 "###);
494 assert_yaml_snapshot!(parse_expr("1 + 2").unwrap(), @r###"
495 ---
496 Binary:
497 left:
498 Literal:
499 Integer: 1
500 op: Add
501 right:
502 Literal:
503 Integer: 2
504 "###)
505 }
506
507 #[test]
508 fn test_string() {
509 let double_quoted_ast = parse_expr(r#"" U S A ""#).unwrap();
510 assert_yaml_snapshot!(double_quoted_ast, @r###"
511 ---
512 Literal:
513 String: " U S A "
514 "###);
515
516 let single_quoted_ast = parse_expr(r#"' U S A '"#).unwrap();
517 assert_eq!(single_quoted_ast, double_quoted_ast);
518
519 assert_yaml_snapshot!(parse_expr(r#""' U S A '""#).unwrap(), @r###"
522 ---
523 Literal:
524 String: "' U S A '"
525 "###);
526 assert_yaml_snapshot!(parse_expr(r#"'" U S A "'"#).unwrap(), @r###"
527 ---
528 Literal:
529 String: "\" U S A \""
530 "###);
531
532 parse_expr(r#"" U S A"#).unwrap_err();
533 parse_expr(r#"" U S A '"#).unwrap_err();
534
535 assert_yaml_snapshot!(parse_expr(r#"" \nU S A ""#).unwrap(), @r###"
536 ---
537 Literal:
538 String: " \nU S A "
539 "###);
540
541 assert_yaml_snapshot!(parse_expr(r#"r" \nU S A ""#).unwrap(), @r###"
542 ---
543 Literal:
544 String: " \\nU S A "
545 "###);
546
547 let multi_double = parse_expr(
548 r#""""
549''
550Canada
551"
552
553""""#,
554 )
555 .unwrap();
556 assert_yaml_snapshot!(multi_double, @r###"
557 ---
558 Literal:
559 String: "\n''\nCanada\n\"\n\n"
560 "###);
561
562 let multi_single = parse_expr(
563 r#"'''
564Canada
565"
566"""
567
568'''"#,
569 )
570 .unwrap();
571 assert_yaml_snapshot!(multi_single, @r###"
572 ---
573 Literal:
574 String: "\nCanada\n\"\n\"\"\"\n\n"
575 "###);
576
577 assert_yaml_snapshot!(
578 parse_expr("''").unwrap(),
579 @r###"
580 ---
581 Literal:
582 String: ""
583 "###);
584 }
585
586 #[test]
587 fn test_s_string() {
588 assert_yaml_snapshot!(parse_expr(r#"s"SUM({col})""#).unwrap(), @r###"
589 ---
590 SString:
591 - String: SUM(
592 - Expr:
593 expr:
594 Ident:
595 - col
596 format: ~
597 - String: )
598 "###);
599 assert_yaml_snapshot!(parse_expr(r#"s"SUM({rel.`Col name`})""#).unwrap(), @r###"
600 ---
601 SString:
602 - String: SUM(
603 - Expr:
604 expr:
605 Ident:
606 - rel
607 - Col name
608 format: ~
609 - String: )
610 "###)
611 }
612
613 #[test]
614 fn test_s_string_braces() {
615 assert_yaml_snapshot!(parse_expr(r#"s"{{?crystal_var}}""#).unwrap(), @r###"
616 ---
617 SString:
618 - String: "{?crystal_var}"
619 "###);
620 assert_yaml_snapshot!(parse_expr(r#"s"foo{{bar""#).unwrap(), @r###"
621 ---
622 SString:
623 - String: "foo{bar"
624 "###);
625 parse_expr(r#"s"foo{{bar}""#).unwrap_err();
626 }
627
628 #[test]
629 fn test_tuple() {
630 assert_yaml_snapshot!(parse_expr(r#"{1 + 1, 2}"#).unwrap(), @r###"
631 ---
632 Tuple:
633 - Binary:
634 left:
635 Literal:
636 Integer: 1
637 op: Add
638 right:
639 Literal:
640 Integer: 1
641 - Literal:
642 Integer: 2
643 "###);
644 assert_yaml_snapshot!(parse_expr(r#"{1 + (f 1), 2}"#).unwrap(), @r###"
645 ---
646 Tuple:
647 - Binary:
648 left:
649 Literal:
650 Integer: 1
651 op: Add
652 right:
653 FuncCall:
654 name:
655 Ident:
656 - f
657 args:
658 - Literal:
659 Integer: 1
660 - Literal:
661 Integer: 2
662 "###);
663 assert_yaml_snapshot!(parse_expr(
665 r#"{1,
666
667 2}"#
668 ).unwrap(), @r###"
669 ---
670 Tuple:
671 - Literal:
672 Integer: 1
673 - Literal:
674 Integer: 2
675 "###);
676 let ab = parse_expr(r#"{a b}"#).unwrap();
678 let a_comma_b = parse_expr(r#"{a, b}"#).unwrap();
679 assert_yaml_snapshot!(ab, @r###"
680 ---
681 Tuple:
682 - FuncCall:
683 name:
684 Ident:
685 - a
686 args:
687 - Ident:
688 - b
689 "###);
690 assert_yaml_snapshot!(a_comma_b, @r###"
691 ---
692 Tuple:
693 - Ident:
694 - a
695 - Ident:
696 - b
697 "###);
698 assert_ne!(ab, a_comma_b);
699
700 assert_yaml_snapshot!(parse_expr(r#"{amount, +amount, -amount}"#).unwrap(), @r###"
701 ---
702 Tuple:
703 - Ident:
704 - amount
705 - Unary:
706 op: Add
707 expr:
708 Ident:
709 - amount
710 - Unary:
711 op: Neg
712 expr:
713 Ident:
714 - amount
715 "###);
716 assert_yaml_snapshot!(parse_expr(r#"{amount, +amount, -amount}"#).unwrap(), @r###"
718 ---
719 Tuple:
720 - Ident:
721 - amount
722 - Unary:
723 op: Add
724 expr:
725 Ident:
726 - amount
727 - Unary:
728 op: Neg
729 expr:
730 Ident:
731 - amount
732 "###);
733 }
734
735 #[test]
736 fn test_number() {
737 assert_yaml_snapshot!(parse_expr(r#"23"#).unwrap(), @r###"
738 ---
739 Literal:
740 Integer: 23
741 "###);
742 assert_yaml_snapshot!(parse_expr(r#"2_3_4.5_6"#).unwrap(), @r###"
743 ---
744 Literal:
745 Float: 234.56
746 "###);
747 assert_yaml_snapshot!(parse_expr(r#"23.6"#).unwrap(), @r###"
748 ---
749 Literal:
750 Float: 23.6
751 "###);
752 assert_yaml_snapshot!(parse_expr(r#"23.0"#).unwrap(), @r###"
753 ---
754 Literal:
755 Float: 23
756 "###);
757 assert_yaml_snapshot!(parse_expr(r#"2 + 2"#).unwrap(), @r###"
758 ---
759 Binary:
760 left:
761 Literal:
762 Integer: 2
763 op: Add
764 right:
765 Literal:
766 Integer: 2
767 "###);
768
769 assert!(parse_expr("_2").unwrap().kind.into_ident().is_ok());
771 assert!(parse_expr("_").unwrap().kind.into_ident().is_ok());
772
773 assert!(parse_expr(r#"add 1. 2"#).is_err());
775
776 assert!(parse_expr("_2.3").is_err());
777
778 assert_yaml_snapshot!(parse_expr(r#"2e3"#).unwrap(), @r###"
779 ---
780 Literal:
781 Float: 2000
782 "###);
783
784 }
787
788 #[test]
789 fn test_filter() {
790 assert_yaml_snapshot!(
791 parse_single(r#"filter country == "USA""#).unwrap(), @r###"
792 ---
793 - Main:
794 FuncCall:
795 name:
796 Ident:
797 - filter
798 args:
799 - Binary:
800 left:
801 Ident:
802 - country
803 op: Eq
804 right:
805 Literal:
806 String: USA
807 annotations: []
808 "###);
809
810 assert_yaml_snapshot!(
811 parse_single(r#"filter (upper country) == "USA""#).unwrap(), @r###"
812 ---
813 - Main:
814 FuncCall:
815 name:
816 Ident:
817 - filter
818 args:
819 - Binary:
820 left:
821 FuncCall:
822 name:
823 Ident:
824 - upper
825 args:
826 - Ident:
827 - country
828 op: Eq
829 right:
830 Literal:
831 String: USA
832 annotations: []
833 "###
834 );
835 }
836
837 #[test]
838 fn test_aggregate() {
839 let aggregate = parse_single(
840 r"group {title} (
841 aggregate {sum salary, count}
842 )",
843 )
844 .unwrap();
845 assert_yaml_snapshot!(
846 aggregate, @r###"
847 ---
848 - Main:
849 FuncCall:
850 name:
851 Ident:
852 - group
853 args:
854 - Tuple:
855 - Ident:
856 - title
857 - FuncCall:
858 name:
859 Ident:
860 - aggregate
861 args:
862 - Tuple:
863 - FuncCall:
864 name:
865 Ident:
866 - sum
867 args:
868 - Ident:
869 - salary
870 - Ident:
871 - count
872 annotations: []
873 "###);
874 let aggregate = parse_single(
875 r"group {title} (
876 aggregate {sum salary}
877 )",
878 )
879 .unwrap();
880 assert_yaml_snapshot!(
881 aggregate, @r###"
882 ---
883 - Main:
884 FuncCall:
885 name:
886 Ident:
887 - group
888 args:
889 - Tuple:
890 - Ident:
891 - title
892 - FuncCall:
893 name:
894 Ident:
895 - aggregate
896 args:
897 - Tuple:
898 - FuncCall:
899 name:
900 Ident:
901 - sum
902 args:
903 - Ident:
904 - salary
905 annotations: []
906 "###);
907 }
908
909 #[test]
910 fn test_derive() {
911 assert_yaml_snapshot!(
912 parse_expr(r#"derive {x = 5, y = (-x)}"#).unwrap()
913 , @r###"
914 ---
915 FuncCall:
916 name:
917 Ident:
918 - derive
919 args:
920 - Tuple:
921 - Literal:
922 Integer: 5
923 alias: x
924 - Unary:
925 op: Neg
926 expr:
927 Ident:
928 - x
929 alias: y
930 "###);
931 }
932
933 #[test]
934 fn test_select() {
935 assert_yaml_snapshot!(
936 parse_expr(r#"select x"#).unwrap()
937 , @r###"
938 ---
939 FuncCall:
940 name:
941 Ident:
942 - select
943 args:
944 - Ident:
945 - x
946 "###);
947
948 assert_yaml_snapshot!(
949 parse_expr(r#"select !{x}"#).unwrap()
950 , @r###"
951 ---
952 FuncCall:
953 name:
954 Ident:
955 - select
956 args:
957 - Unary:
958 op: Not
959 expr:
960 Tuple:
961 - Ident:
962 - x
963 "###);
964
965 assert_yaml_snapshot!(
966 parse_expr(r#"select {x, y}"#).unwrap()
967 , @r###"
968 ---
969 FuncCall:
970 name:
971 Ident:
972 - select
973 args:
974 - Tuple:
975 - Ident:
976 - x
977 - Ident:
978 - y
979 "###);
980 }
981
982 #[test]
983 fn test_expr() {
984 assert_yaml_snapshot!(
985 parse_expr(r#"country == "USA""#).unwrap()
986 , @r###"
987 ---
988 Binary:
989 left:
990 Ident:
991 - country
992 op: Eq
993 right:
994 Literal:
995 String: USA
996 "###);
997 assert_yaml_snapshot!(parse_expr(
998 r#"{
999 gross_salary = salary + payroll_tax,
1000 gross_cost = gross_salary + benefits_cost,
1001}"#).unwrap(), @r###"
1002 ---
1003 Tuple:
1004 - Binary:
1005 left:
1006 Ident:
1007 - salary
1008 op: Add
1009 right:
1010 Ident:
1011 - payroll_tax
1012 alias: gross_salary
1013 - Binary:
1014 left:
1015 Ident:
1016 - gross_salary
1017 op: Add
1018 right:
1019 Ident:
1020 - benefits_cost
1021 alias: gross_cost
1022 "###);
1023 assert_yaml_snapshot!(
1024 parse_expr(
1025 "(salary + payroll_tax) * (1 + tax_rate)"
1026 ).unwrap(),
1027 @r###"
1028 ---
1029 Binary:
1030 left:
1031 Binary:
1032 left:
1033 Ident:
1034 - salary
1035 op: Add
1036 right:
1037 Ident:
1038 - payroll_tax
1039 op: Mul
1040 right:
1041 Binary:
1042 left:
1043 Literal:
1044 Integer: 1
1045 op: Add
1046 right:
1047 Ident:
1048 - tax_rate
1049 "###);
1050 }
1051
1052 #[test]
1053 fn test_regex() {
1054 assert_yaml_snapshot!(
1055 parse_expr(
1056 "'oba' ~= 'foobar'"
1057 ).unwrap(),
1058 @r###"
1059 ---
1060 Binary:
1061 left:
1062 Literal:
1063 String: oba
1064 op: RegexSearch
1065 right:
1066 Literal:
1067 String: foobar
1068 "###);
1069 }
1070
1071 #[test]
1072 fn test_function() {
1073 assert_yaml_snapshot!(parse_single("let plus_one = x -> x + 1\n").unwrap(), @r###"
1074 ---
1075 - VarDef:
1076 name: plus_one
1077 value:
1078 Func:
1079 return_ty: ~
1080 body:
1081 Binary:
1082 left:
1083 Ident:
1084 - x
1085 op: Add
1086 right:
1087 Literal:
1088 Integer: 1
1089 params:
1090 - name: x
1091 default_value: ~
1092 named_params: []
1093 ty_expr: ~
1094 kind: Let
1095 annotations: []
1096 "###);
1097 assert_yaml_snapshot!(parse_single("let identity = x -> x\n").unwrap()
1098 , @r###"
1099 ---
1100 - VarDef:
1101 name: identity
1102 value:
1103 Func:
1104 return_ty: ~
1105 body:
1106 Ident:
1107 - x
1108 params:
1109 - name: x
1110 default_value: ~
1111 named_params: []
1112 ty_expr: ~
1113 kind: Let
1114 annotations: []
1115 "###);
1116 assert_yaml_snapshot!(parse_single("let plus_one = x -> (x + 1)\n").unwrap()
1117 , @r###"
1118 ---
1119 - VarDef:
1120 name: plus_one
1121 value:
1122 Func:
1123 return_ty: ~
1124 body:
1125 Binary:
1126 left:
1127 Ident:
1128 - x
1129 op: Add
1130 right:
1131 Literal:
1132 Integer: 1
1133 params:
1134 - name: x
1135 default_value: ~
1136 named_params: []
1137 ty_expr: ~
1138 kind: Let
1139 annotations: []
1140 "###);
1141 assert_yaml_snapshot!(parse_single("let plus_one = x -> x + 1\n").unwrap()
1142 , @r###"
1143 ---
1144 - VarDef:
1145 name: plus_one
1146 value:
1147 Func:
1148 return_ty: ~
1149 body:
1150 Binary:
1151 left:
1152 Ident:
1153 - x
1154 op: Add
1155 right:
1156 Literal:
1157 Integer: 1
1158 params:
1159 - name: x
1160 default_value: ~
1161 named_params: []
1162 ty_expr: ~
1163 kind: Let
1164 annotations: []
1165 "###);
1166
1167 assert_yaml_snapshot!(parse_single("let foo = x -> some_func (foo bar + 1) (plax) - baz\n").unwrap()
1168 , @r###"
1169 ---
1170 - VarDef:
1171 name: foo
1172 value:
1173 Func:
1174 return_ty: ~
1175 body:
1176 FuncCall:
1177 name:
1178 Ident:
1179 - some_func
1180 args:
1181 - FuncCall:
1182 name:
1183 Ident:
1184 - foo
1185 args:
1186 - Binary:
1187 left:
1188 Ident:
1189 - bar
1190 op: Add
1191 right:
1192 Literal:
1193 Integer: 1
1194 - Binary:
1195 left:
1196 Ident:
1197 - plax
1198 op: Sub
1199 right:
1200 Ident:
1201 - baz
1202 params:
1203 - name: x
1204 default_value: ~
1205 named_params: []
1206 ty_expr: ~
1207 kind: Let
1208 annotations: []
1209 "###);
1210
1211 assert_yaml_snapshot!(parse_single("func return_constant -> 42\n").unwrap(), @r###"
1212 ---
1213 - Main:
1214 Func:
1215 return_ty: ~
1216 body:
1217 Literal:
1218 Integer: 42
1219 params:
1220 - name: return_constant
1221 default_value: ~
1222 named_params: []
1223 annotations: []
1224 "###);
1225
1226 assert_yaml_snapshot!(parse_single(r#"let count = X -> s"SUM({X})"
1227 "#).unwrap(), @r###"
1228 ---
1229 - VarDef:
1230 name: count
1231 value:
1232 Func:
1233 return_ty: ~
1234 body:
1235 SString:
1236 - String: SUM(
1237 - Expr:
1238 expr:
1239 Ident:
1240 - X
1241 format: ~
1242 - String: )
1243 params:
1244 - name: X
1245 default_value: ~
1246 named_params: []
1247 ty_expr: ~
1248 kind: Let
1249 annotations: []
1250 "###);
1251
1252 assert_yaml_snapshot!(parse_single(
1253 r#"
1254 let lag_day = x -> (
1255 window x
1256 by sec_id
1257 sort date
1258 lag 1
1259 )
1260 "#
1261 )
1262 .unwrap(), @r###"
1263 ---
1264 - VarDef:
1265 name: lag_day
1266 value:
1267 Func:
1268 return_ty: ~
1269 body:
1270 Pipeline:
1271 exprs:
1272 - FuncCall:
1273 name:
1274 Ident:
1275 - window
1276 args:
1277 - Ident:
1278 - x
1279 - FuncCall:
1280 name:
1281 Ident:
1282 - by
1283 args:
1284 - Ident:
1285 - sec_id
1286 - FuncCall:
1287 name:
1288 Ident:
1289 - sort
1290 args:
1291 - Ident:
1292 - date
1293 - FuncCall:
1294 name:
1295 Ident:
1296 - lag
1297 args:
1298 - Literal:
1299 Integer: 1
1300 params:
1301 - name: x
1302 default_value: ~
1303 named_params: []
1304 ty_expr: ~
1305 kind: Let
1306 annotations: []
1307 "###);
1308
1309 assert_yaml_snapshot!(parse_single("let add = x to:a -> x + to\n").unwrap(), @r###"
1310 ---
1311 - VarDef:
1312 name: add
1313 value:
1314 Func:
1315 return_ty: ~
1316 body:
1317 Binary:
1318 left:
1319 Ident:
1320 - x
1321 op: Add
1322 right:
1323 Ident:
1324 - to
1325 params:
1326 - name: x
1327 default_value: ~
1328 named_params:
1329 - name: to
1330 default_value:
1331 Ident:
1332 - a
1333 ty_expr: ~
1334 kind: Let
1335 annotations: []
1336 "###);
1337 }
1338
1339 #[test]
1340 fn test_func_call() {
1341 let ast = parse_expr(r#"count"#).unwrap();
1343 let ident = ast.kind.into_ident().unwrap();
1344 assert_yaml_snapshot!(
1345 ident, @r###"
1346 ---
1347 - count
1348 "###);
1349
1350 let ast = parse_expr(r#"s 'foo'"#).unwrap();
1351 assert_yaml_snapshot!(
1352 ast, @r###"
1353 ---
1354 FuncCall:
1355 name:
1356 Ident:
1357 - s
1358 args:
1359 - Literal:
1360 String: foo
1361 "###);
1362
1363 let ast = parse_expr(r#"count s'*'"#).unwrap();
1365 let func_call: FuncCall = ast.kind.into_func_call().unwrap();
1366 assert_yaml_snapshot!(
1367 func_call, @r###"
1368 ---
1369 name:
1370 Ident:
1371 - count
1372 args:
1373 - SString:
1374 - String: "*"
1375 "###);
1376
1377 parse_expr("plus_one x:0 x:0 ").unwrap_err();
1378
1379 let ast = parse_expr(r#"add bar to=3"#).unwrap();
1380 assert_yaml_snapshot!(
1381 ast, @r###"
1382 ---
1383 FuncCall:
1384 name:
1385 Ident:
1386 - add
1387 args:
1388 - Ident:
1389 - bar
1390 - Literal:
1391 Integer: 3
1392 alias: to
1393 "###);
1394 }
1395
1396 #[test]
1397 fn test_op_precedence() {
1398 assert_yaml_snapshot!(parse_expr(r#"1 + 2 - 3 - 4"#).unwrap(), @r###"
1399 ---
1400 Binary:
1401 left:
1402 Binary:
1403 left:
1404 Binary:
1405 left:
1406 Literal:
1407 Integer: 1
1408 op: Add
1409 right:
1410 Literal:
1411 Integer: 2
1412 op: Sub
1413 right:
1414 Literal:
1415 Integer: 3
1416 op: Sub
1417 right:
1418 Literal:
1419 Integer: 4
1420 "###);
1421
1422 assert_yaml_snapshot!(parse_expr(r#"1 / 2 - 3 * 4 + 1"#).unwrap(), @r###"
1423 ---
1424 Binary:
1425 left:
1426 Binary:
1427 left:
1428 Binary:
1429 left:
1430 Literal:
1431 Integer: 1
1432 op: DivFloat
1433 right:
1434 Literal:
1435 Integer: 2
1436 op: Sub
1437 right:
1438 Binary:
1439 left:
1440 Literal:
1441 Integer: 3
1442 op: Mul
1443 right:
1444 Literal:
1445 Integer: 4
1446 op: Add
1447 right:
1448 Literal:
1449 Integer: 1
1450 "###);
1451
1452 assert_yaml_snapshot!(parse_expr(r#"a && b || !c && d"#).unwrap(), @r###"
1453 ---
1454 Binary:
1455 left:
1456 Binary:
1457 left:
1458 Ident:
1459 - a
1460 op: And
1461 right:
1462 Ident:
1463 - b
1464 op: Or
1465 right:
1466 Binary:
1467 left:
1468 Unary:
1469 op: Not
1470 expr:
1471 Ident:
1472 - c
1473 op: And
1474 right:
1475 Ident:
1476 - d
1477 "###);
1478
1479 assert_yaml_snapshot!(parse_expr(r#"a && b + c || (d e) && f"#).unwrap(), @r###"
1480 ---
1481 Binary:
1482 left:
1483 Binary:
1484 left:
1485 Ident:
1486 - a
1487 op: And
1488 right:
1489 Binary:
1490 left:
1491 Ident:
1492 - b
1493 op: Add
1494 right:
1495 Ident:
1496 - c
1497 op: Or
1498 right:
1499 Binary:
1500 left:
1501 FuncCall:
1502 name:
1503 Ident:
1504 - d
1505 args:
1506 - Ident:
1507 - e
1508 op: And
1509 right:
1510 Ident:
1511 - f
1512 "###);
1513 }
1514
1515 #[test]
1516 fn test_var_def() {
1517 assert_yaml_snapshot!(parse_single(
1518 "let newest_employees = (from employees)"
1519 ).unwrap(), @r###"
1520 ---
1521 - VarDef:
1522 name: newest_employees
1523 value:
1524 FuncCall:
1525 name:
1526 Ident:
1527 - from
1528 args:
1529 - Ident:
1530 - employees
1531 ty_expr: ~
1532 kind: Let
1533 annotations: []
1534 "###);
1535
1536 assert_yaml_snapshot!(parse_single(
1537 r#"
1538 let newest_employees = (
1539 from employees
1540 group country (
1541 aggregate {
1542 average_country_salary = average salary
1543 }
1544 )
1545 sort tenure
1546 take 50
1547 )"#.trim()).unwrap(),
1548 @r###"
1549 ---
1550 - VarDef:
1551 name: newest_employees
1552 value:
1553 Pipeline:
1554 exprs:
1555 - FuncCall:
1556 name:
1557 Ident:
1558 - from
1559 args:
1560 - Ident:
1561 - employees
1562 - FuncCall:
1563 name:
1564 Ident:
1565 - group
1566 args:
1567 - Ident:
1568 - country
1569 - FuncCall:
1570 name:
1571 Ident:
1572 - aggregate
1573 args:
1574 - Tuple:
1575 - FuncCall:
1576 name:
1577 Ident:
1578 - average
1579 args:
1580 - Ident:
1581 - salary
1582 alias: average_country_salary
1583 - FuncCall:
1584 name:
1585 Ident:
1586 - sort
1587 args:
1588 - Ident:
1589 - tenure
1590 - FuncCall:
1591 name:
1592 Ident:
1593 - take
1594 args:
1595 - Literal:
1596 Integer: 50
1597 ty_expr: ~
1598 kind: Let
1599 annotations: []
1600 "###);
1601
1602 assert_yaml_snapshot!(parse_single(r#"
1603 let e = s"SELECT * FROM employees"
1604 "#).unwrap(), @r###"
1605 ---
1606 - VarDef:
1607 name: e
1608 value:
1609 SString:
1610 - String: SELECT * FROM employees
1611 ty_expr: ~
1612 kind: Let
1613 annotations: []
1614 "###);
1615
1616 assert_yaml_snapshot!(parse_single(
1617 "let x = (
1618
1619 from x_table
1620
1621 select only_in_x = foo
1622
1623 )
1624
1625 from x"
1626 ).unwrap(), @r###"
1627 ---
1628 - VarDef:
1629 name: x
1630 value:
1631 Pipeline:
1632 exprs:
1633 - FuncCall:
1634 name:
1635 Ident:
1636 - from
1637 args:
1638 - Ident:
1639 - x_table
1640 - FuncCall:
1641 name:
1642 Ident:
1643 - select
1644 args:
1645 - Ident:
1646 - foo
1647 alias: only_in_x
1648 ty_expr: ~
1649 kind: Let
1650 annotations: []
1651 - Main:
1652 FuncCall:
1653 name:
1654 Ident:
1655 - from
1656 args:
1657 - Ident:
1658 - x
1659 annotations: []
1660 "###);
1661 }
1662
1663 #[test]
1664 fn test_inline_pipeline() {
1665 assert_yaml_snapshot!(parse_expr("(salary | percentile 50)").unwrap(), @r###"
1666 ---
1667 Pipeline:
1668 exprs:
1669 - Ident:
1670 - salary
1671 - FuncCall:
1672 name:
1673 Ident:
1674 - percentile
1675 args:
1676 - Literal:
1677 Integer: 50
1678 "###);
1679 assert_yaml_snapshot!(parse_single("let median = x -> (x | percentile 50)\n").unwrap(), @r###"
1680 ---
1681 - VarDef:
1682 name: median
1683 value:
1684 Func:
1685 return_ty: ~
1686 body:
1687 Pipeline:
1688 exprs:
1689 - Ident:
1690 - x
1691 - FuncCall:
1692 name:
1693 Ident:
1694 - percentile
1695 args:
1696 - Literal:
1697 Integer: 50
1698 params:
1699 - name: x
1700 default_value: ~
1701 named_params: []
1702 ty_expr: ~
1703 kind: Let
1704 annotations: []
1705 "###);
1706 }
1707
1708 #[test]
1709 fn test_sql_parameters() {
1710 assert_yaml_snapshot!(parse_single(r#"
1711 from mytable
1712 filter {
1713 first_name == $1,
1714 last_name == $2.name
1715 }
1716 "#).unwrap(), @r###"
1717 ---
1718 - Main:
1719 Pipeline:
1720 exprs:
1721 - FuncCall:
1722 name:
1723 Ident:
1724 - from
1725 args:
1726 - Ident:
1727 - mytable
1728 - FuncCall:
1729 name:
1730 Ident:
1731 - filter
1732 args:
1733 - Tuple:
1734 - Binary:
1735 left:
1736 Ident:
1737 - first_name
1738 op: Eq
1739 right:
1740 Param: "1"
1741 - Binary:
1742 left:
1743 Ident:
1744 - last_name
1745 op: Eq
1746 right:
1747 Param: 2.name
1748 annotations: []
1749 "###);
1750 }
1751
1752 #[test]
1753 fn test_tab_characters() {
1754 parse_single(
1756 "from c_invoice
1757join doc:c_doctype (==c_invoice_id)
1758select [
1759\tinvoice_no,
1760\tdocstatus
1761]",
1762 )
1763 .unwrap();
1764 }
1765
1766 #[test]
1767 fn test_backticks() {
1768 let prql = "
1769from `a/*.parquet`
1770aggregate {max c}
1771join `schema.table` (==id)
1772join `my-proj.dataset.table`
1773join `my-proj`.`dataset`.`table`
1774";
1775
1776 assert_yaml_snapshot!(parse_single(prql).unwrap(), @r###"
1777 ---
1778 - Main:
1779 Pipeline:
1780 exprs:
1781 - FuncCall:
1782 name:
1783 Ident:
1784 - from
1785 args:
1786 - Ident:
1787 - a/*.parquet
1788 - FuncCall:
1789 name:
1790 Ident:
1791 - aggregate
1792 args:
1793 - Tuple:
1794 - FuncCall:
1795 name:
1796 Ident:
1797 - max
1798 args:
1799 - Ident:
1800 - c
1801 - FuncCall:
1802 name:
1803 Ident:
1804 - join
1805 args:
1806 - Ident:
1807 - schema.table
1808 - Unary:
1809 op: EqSelf
1810 expr:
1811 Ident:
1812 - id
1813 - FuncCall:
1814 name:
1815 Ident:
1816 - join
1817 args:
1818 - Ident:
1819 - my-proj.dataset.table
1820 - FuncCall:
1821 name:
1822 Ident:
1823 - join
1824 args:
1825 - Ident:
1826 - my-proj
1827 - dataset
1828 - table
1829 annotations: []
1830 "###);
1831 }
1832
1833 #[test]
1834 fn test_sort() {
1835 assert_yaml_snapshot!(parse_single("
1836 from invoices
1837 sort issued_at
1838 sort (-issued_at)
1839 sort {issued_at}
1840 sort {-issued_at}
1841 sort {issued_at, -amount, +num_of_articles}
1842 ").unwrap(), @r###"
1843 ---
1844 - Main:
1845 Pipeline:
1846 exprs:
1847 - FuncCall:
1848 name:
1849 Ident:
1850 - from
1851 args:
1852 - Ident:
1853 - invoices
1854 - FuncCall:
1855 name:
1856 Ident:
1857 - sort
1858 args:
1859 - Ident:
1860 - issued_at
1861 - FuncCall:
1862 name:
1863 Ident:
1864 - sort
1865 args:
1866 - Unary:
1867 op: Neg
1868 expr:
1869 Ident:
1870 - issued_at
1871 - FuncCall:
1872 name:
1873 Ident:
1874 - sort
1875 args:
1876 - Tuple:
1877 - Ident:
1878 - issued_at
1879 - FuncCall:
1880 name:
1881 Ident:
1882 - sort
1883 args:
1884 - Tuple:
1885 - Unary:
1886 op: Neg
1887 expr:
1888 Ident:
1889 - issued_at
1890 - FuncCall:
1891 name:
1892 Ident:
1893 - sort
1894 args:
1895 - Tuple:
1896 - Ident:
1897 - issued_at
1898 - Unary:
1899 op: Neg
1900 expr:
1901 Ident:
1902 - amount
1903 - Unary:
1904 op: Add
1905 expr:
1906 Ident:
1907 - num_of_articles
1908 annotations: []
1909 "###);
1910 }
1911
1912 #[test]
1913 fn test_dates() {
1914 assert_yaml_snapshot!(parse_single("
1915 from employees
1916 derive {age_plus_two_years = (age + 2years)}
1917 ").unwrap(), @r###"
1918 ---
1919 - Main:
1920 Pipeline:
1921 exprs:
1922 - FuncCall:
1923 name:
1924 Ident:
1925 - from
1926 args:
1927 - Ident:
1928 - employees
1929 - FuncCall:
1930 name:
1931 Ident:
1932 - derive
1933 args:
1934 - Tuple:
1935 - Binary:
1936 left:
1937 Ident:
1938 - age
1939 op: Add
1940 right:
1941 Literal:
1942 ValueAndUnit:
1943 n: 2
1944 unit: years
1945 alias: age_plus_two_years
1946 annotations: []
1947 "###);
1948
1949 assert_yaml_snapshot!(parse_expr("@2011-02-01").unwrap(), @r###"
1950 ---
1951 Literal:
1952 Date: 2011-02-01
1953 "###);
1954 assert_yaml_snapshot!(parse_expr("@2011-02-01T10:00").unwrap(), @r###"
1955 ---
1956 Literal:
1957 Timestamp: "2011-02-01T10:00"
1958 "###);
1959 assert_yaml_snapshot!(parse_expr("@14:00").unwrap(), @r###"
1960 ---
1961 Literal:
1962 Time: "14:00"
1963 "###);
1964 parse_expr("@2020-01-0").unwrap_err();
1967
1968 parse_expr("@2020-01-011").unwrap_err();
1969
1970 parse_expr("@2020-01-01T111").unwrap_err();
1971 }
1972
1973 #[test]
1974 fn test_multiline_string() {
1975 assert_yaml_snapshot!(parse_single(r##"
1976 derive x = r#"r-string test"#
1977 "##).unwrap(), @r###"
1978 ---
1979 - Main:
1980 FuncCall:
1981 name:
1982 Ident:
1983 - derive
1984 args:
1985 - Ident:
1986 - r
1987 alias: x
1988 annotations: []
1989 "### )
1990 }
1991
1992 #[test]
1993 fn test_coalesce() {
1994 assert_yaml_snapshot!(parse_single(r###"
1995 from employees
1996 derive amount = amount ?? 0
1997 "###).unwrap(), @r###"
1998 ---
1999 - Main:
2000 Pipeline:
2001 exprs:
2002 - FuncCall:
2003 name:
2004 Ident:
2005 - from
2006 args:
2007 - Ident:
2008 - employees
2009 - FuncCall:
2010 name:
2011 Ident:
2012 - derive
2013 args:
2014 - Binary:
2015 left:
2016 Ident:
2017 - amount
2018 op: Coalesce
2019 right:
2020 Literal:
2021 Integer: 0
2022 alias: amount
2023 annotations: []
2024 "### )
2025 }
2026
2027 #[test]
2028 fn test_literal() {
2029 assert_yaml_snapshot!(parse_single(r###"
2030 derive x = true
2031 "###).unwrap(), @r###"
2032 ---
2033 - Main:
2034 FuncCall:
2035 name:
2036 Ident:
2037 - derive
2038 args:
2039 - Literal:
2040 Boolean: true
2041 alias: x
2042 annotations: []
2043 "###)
2044 }
2045
2046 #[test]
2047 fn test_allowed_idents() {
2048 assert_yaml_snapshot!(parse_single(r###"
2049 from employees
2050 join _salary (==employee_id) # table with leading underscore
2051 filter first_name == $1
2052 select {_employees._underscored_column}
2053 "###).unwrap(), @r###"
2054 ---
2055 - Main:
2056 Pipeline:
2057 exprs:
2058 - FuncCall:
2059 name:
2060 Ident:
2061 - from
2062 args:
2063 - Ident:
2064 - employees
2065 - FuncCall:
2066 name:
2067 Ident:
2068 - join
2069 args:
2070 - Ident:
2071 - _salary
2072 - Unary:
2073 op: EqSelf
2074 expr:
2075 Ident:
2076 - employee_id
2077 - FuncCall:
2078 name:
2079 Ident:
2080 - filter
2081 args:
2082 - Binary:
2083 left:
2084 Ident:
2085 - first_name
2086 op: Eq
2087 right:
2088 Param: "1"
2089 - FuncCall:
2090 name:
2091 Ident:
2092 - select
2093 args:
2094 - Tuple:
2095 - Ident:
2096 - _employees
2097 - _underscored_column
2098 annotations: []
2099 "###)
2100 }
2101
2102 #[test]
2103 fn test_gt_lt_gte_lte() {
2104 assert_yaml_snapshot!(parse_single(r###"
2105 from people
2106 filter age >= 100
2107 filter num_grandchildren <= 10
2108 filter salary > 0
2109 filter num_eyes < 2
2110 "###).unwrap(), @r###"
2111 ---
2112 - Main:
2113 Pipeline:
2114 exprs:
2115 - FuncCall:
2116 name:
2117 Ident:
2118 - from
2119 args:
2120 - Ident:
2121 - people
2122 - FuncCall:
2123 name:
2124 Ident:
2125 - filter
2126 args:
2127 - Binary:
2128 left:
2129 Ident:
2130 - age
2131 op: Gte
2132 right:
2133 Literal:
2134 Integer: 100
2135 - FuncCall:
2136 name:
2137 Ident:
2138 - filter
2139 args:
2140 - Binary:
2141 left:
2142 Ident:
2143 - num_grandchildren
2144 op: Lte
2145 right:
2146 Literal:
2147 Integer: 10
2148 - FuncCall:
2149 name:
2150 Ident:
2151 - filter
2152 args:
2153 - Binary:
2154 left:
2155 Ident:
2156 - salary
2157 op: Gt
2158 right:
2159 Literal:
2160 Integer: 0
2161 - FuncCall:
2162 name:
2163 Ident:
2164 - filter
2165 args:
2166 - Binary:
2167 left:
2168 Ident:
2169 - num_eyes
2170 op: Lt
2171 right:
2172 Literal:
2173 Integer: 2
2174 annotations: []
2175 "###)
2176 }
2177
2178 #[test]
2179 fn test_assign() {
2180 assert_yaml_snapshot!(parse_single(r###"
2181from employees
2182join s=salaries (==id)
2183 "###).unwrap(), @r###"
2184 ---
2185 - Main:
2186 Pipeline:
2187 exprs:
2188 - FuncCall:
2189 name:
2190 Ident:
2191 - from
2192 args:
2193 - Ident:
2194 - employees
2195 - FuncCall:
2196 name:
2197 Ident:
2198 - join
2199 args:
2200 - Ident:
2201 - salaries
2202 alias: s
2203 - Unary:
2204 op: EqSelf
2205 expr:
2206 Ident:
2207 - id
2208 annotations: []
2209 "###);
2210 }
2211
2212 #[test]
2213 fn test_ident_with_keywords() {
2214 assert_yaml_snapshot!(parse_expr(r"select {andrew, orion, lettuce, falsehood, null0}").unwrap(), @r###"
2215 ---
2216 FuncCall:
2217 name:
2218 Ident:
2219 - select
2220 args:
2221 - Tuple:
2222 - Ident:
2223 - andrew
2224 - Ident:
2225 - orion
2226 - Ident:
2227 - lettuce
2228 - Ident:
2229 - falsehood
2230 - Ident:
2231 - null0
2232 "###);
2233
2234 assert_yaml_snapshot!(parse_expr(r"{false}").unwrap(), @r###"
2235 ---
2236 Tuple:
2237 - Literal:
2238 Boolean: false
2239 "###);
2240 }
2241
2242 #[test]
2243 fn test_case() {
2244 assert_yaml_snapshot!(parse_expr(r#"case {
2245 nickname != null => nickname,
2246 true => null
2247 }"#).unwrap(), @r###"
2248 ---
2249 Case:
2250 - condition:
2251 Binary:
2252 left:
2253 Ident:
2254 - nickname
2255 op: Ne
2256 right:
2257 Literal: "Null"
2258 value:
2259 Ident:
2260 - nickname
2261 - condition:
2262 Literal:
2263 Boolean: true
2264 value:
2265 Literal: "Null"
2266 "###);
2267 }
2268
2269 #[test]
2270 fn test_params() {
2271 assert_yaml_snapshot!(parse_expr(r#"$2"#).unwrap(), @r###"
2272 ---
2273 Param: "2"
2274 "###);
2275
2276 assert_yaml_snapshot!(parse_expr(r#"$2_any_text"#).unwrap(), @r###"
2277 ---
2278 Param: 2_any_text
2279 "###);
2280 }
2281
2282 #[test]
2283 fn test_unicode() {
2284 let source = "from tète";
2285 assert_yaml_snapshot!(parse_single(source).unwrap(), @r###"
2286 ---
2287 - Main:
2288 FuncCall:
2289 name:
2290 Ident:
2291 - from
2292 args:
2293 - Ident:
2294 - tète
2295 annotations: []
2296 "###);
2297 }
2298
2299 #[test]
2300 fn test_var_defs() {
2301 assert_yaml_snapshot!(parse_single(r#"
2302 let a = (
2303 x
2304 )
2305 "#).unwrap(), @r###"
2306 ---
2307 - VarDef:
2308 name: a
2309 value:
2310 Ident:
2311 - x
2312 ty_expr: ~
2313 kind: Let
2314 annotations: []
2315 "###);
2316
2317 assert_yaml_snapshot!(parse_single(r#"
2318 x
2319 into a
2320 "#).unwrap(), @r###"
2321 ---
2322 - VarDef:
2323 name: a
2324 value:
2325 Ident:
2326 - x
2327 ty_expr: ~
2328 kind: Into
2329 annotations: []
2330 "###);
2331
2332 assert_yaml_snapshot!(parse_single(r#"
2333 x
2334 "#).unwrap(), @r###"
2335 ---
2336 - Main:
2337 Ident:
2338 - x
2339 annotations: []
2340 "###);
2341 }
2342
2343 #[test]
2344 fn test_array() {
2345 assert_yaml_snapshot!(parse_single(r#"
2346 let a = [1, 2,]
2347 let a = [false, "hello"]
2348 "#).unwrap(), @r###"
2349 ---
2350 - VarDef:
2351 name: a
2352 value:
2353 Array:
2354 - Literal:
2355 Integer: 1
2356 - Literal:
2357 Integer: 2
2358 ty_expr: ~
2359 kind: Let
2360 annotations: []
2361 - VarDef:
2362 name: a
2363 value:
2364 Array:
2365 - Literal:
2366 Boolean: false
2367 - Literal:
2368 String: hello
2369 ty_expr: ~
2370 kind: Let
2371 annotations: []
2372 "###);
2373 }
2374
2375 #[test]
2376 fn test_annotation() {
2377 assert_yaml_snapshot!(parse_single(r#"
2378 @{binding_strength=1}
2379 let add = a b -> a + b
2380 "#).unwrap(), @r###"
2381 ---
2382 - VarDef:
2383 name: add
2384 value:
2385 Func:
2386 return_ty: ~
2387 body:
2388 Binary:
2389 left:
2390 Ident:
2391 - a
2392 op: Add
2393 right:
2394 Ident:
2395 - b
2396 params:
2397 - name: a
2398 default_value: ~
2399 - name: b
2400 default_value: ~
2401 named_params: []
2402 ty_expr: ~
2403 kind: Let
2404 annotations:
2405 - expr:
2406 Tuple:
2407 - Literal:
2408 Integer: 1
2409 alias: binding_strength
2410 "###);
2411 parse_single(
2412 r#"
2413 @{binding_strength=1} let add = a b -> a + b
2414 "#,
2415 )
2416 .unwrap();
2417
2418 parse_single(
2419 r#"
2420 @{binding_strength=1}
2421 # comment
2422 let add = a b -> a + b
2423 "#,
2424 )
2425 .unwrap();
2426
2427 parse_single(
2428 r#"
2429 @{binding_strength=1}
2430
2431
2432 let add = a b -> a + b
2433 "#,
2434 )
2435 .unwrap();
2436 }
2437
2438 #[test]
2439 fn check_valid_version() {
2440 let stmt = format!(
2441 r#"
2442 prql version:"{}"
2443 "#,
2444 env!("CARGO_PKG_VERSION_MAJOR")
2445 );
2446 assert!(parse_single(&stmt).is_ok());
2447
2448 let stmt = format!(
2449 r#"
2450 prql version:"{}.{}"
2451 "#,
2452 env!("CARGO_PKG_VERSION_MAJOR"),
2453 env!("CARGO_PKG_VERSION_MINOR")
2454 );
2455 assert!(parse_single(&stmt).is_ok());
2456
2457 let stmt = format!(
2458 r#"
2459 prql version:"{}.{}.{}"
2460 "#,
2461 env!("CARGO_PKG_VERSION_MAJOR"),
2462 env!("CARGO_PKG_VERSION_MINOR"),
2463 env!("CARGO_PKG_VERSION_PATCH"),
2464 );
2465 assert!(parse_single(&stmt).is_ok());
2466 }
2467
2468 #[test]
2469 fn check_invalid_version() {
2470 let stmt = format!(
2471 "prql version:{}\n",
2472 env!("CARGO_PKG_VERSION_MAJOR").parse::<usize>().unwrap() + 1
2473 );
2474 assert!(parse_single(&stmt).is_err());
2475 }
2476
2477 #[test]
2478 fn test_target() {
2479 assert_yaml_snapshot!(parse_single(
2480 r#"
2481 prql target:sql.sqlite
2482
2483 from film
2484 remove film2
2485 "#,
2486 )
2487 .unwrap(), @r###"
2488 ---
2489 - QueryDef:
2490 version: ~
2491 other:
2492 target: sql.sqlite
2493 annotations: []
2494 - Main:
2495 Pipeline:
2496 exprs:
2497 - FuncCall:
2498 name:
2499 Ident:
2500 - from
2501 args:
2502 - Ident:
2503 - film
2504 - FuncCall:
2505 name:
2506 Ident:
2507 - remove
2508 args:
2509 - Ident:
2510 - film2
2511 annotations: []
2512 "###);
2513 }
2514}