Skip to main content

openpql_range_parser/ast/
expr.rs

1use super::{LocInfo, Term};
2
3/// Parsed range expression tree.
4#[derive(PartialEq, Eq, Debug)]
5pub enum Expr {
6    /// Exclusion `A!B`.
7    Not(Box<Self>, Box<Self>),
8    /// Intersection `A:B`.
9    And(Box<Self>, Box<Self>),
10    /// Union `A,B`.
11    Or(Box<Self>, Box<Self>),
12    /// Leaf term with its source span.
13    Term(Term, LocInfo),
14}
15
16impl From<(Term, LocInfo)> for Expr {
17    fn from((t, loc): (Term, LocInfo)) -> Self {
18        Self::Term(t, loc)
19    }
20}
21
22#[cfg(test)]
23#[cfg_attr(coverage_nightly, coverage(off))]
24mod tests {
25    use super::*;
26    use crate::*;
27
28    fn assert_expr(s: &str, expected: Expr) {
29        assert_eq!(
30            *parse_expr(false, s).unwrap(),
31            expected,
32            "{s} != {expected:?}"
33        );
34    }
35
36    fn term_loc(s: &str, a: Loc, b: Loc) -> (Term, LocInfo) {
37        (parse_term(s).unwrap(), (a, b))
38    }
39
40    fn binop<S, T>(l: S, r: T, f: fn(Box<Expr>, Box<Expr>) -> Expr) -> Expr
41    where
42        Expr: From<S> + From<T>,
43    {
44        f(Box::new(Expr::from(l)), Box::new(Expr::from(r)))
45    }
46
47    fn not<S, T>(l: S, r: T) -> Expr
48    where
49        Expr: From<S> + From<T>,
50    {
51        binop(l, r, Expr::Not)
52    }
53
54    fn and<S, T>(l: S, r: T) -> Expr
55    where
56        Expr: From<S> + From<T>,
57    {
58        binop(l, r, Expr::And)
59    }
60
61    fn or<S, T>(l: S, r: T) -> Expr
62    where
63        Expr: From<S> + From<T>,
64    {
65        binop(l, r, Expr::Or)
66    }
67
68    #[test]
69    fn test_expr_term() {
70        assert_expr("AsA", term_loc("AsA", 0, 3).into());
71    }
72
73    #[test]
74    fn test_expr_and() {
75        assert_expr("AsA:ss", and(term_loc("AsA", 0, 3), term_loc("ss", 4, 6)));
76    }
77
78    #[test]
79    fn test_expr_or() {
80        assert_expr("AsA,ss", or(term_loc("AsA", 0, 3), term_loc("ss", 4, 6)));
81    }
82
83    #[test]
84    fn test_expr_not() {
85        assert_expr("AsA!ss", not(term_loc("AsA", 0, 3), term_loc("ss", 4, 6)));
86    }
87
88    #[test]
89    fn test_expr_precedence() {
90        assert_expr(
91            "A:B!c,d",
92            or(
93                and(
94                    term_loc("A", 0, 1),
95                    not(term_loc("B", 2, 3), term_loc("c", 4, 5)),
96                ),
97                term_loc("d", 6, 7),
98            ),
99        );
100
101        assert_expr(
102            "A:B!(c,d)",
103            and(
104                term_loc("A", 0, 1),
105                not(
106                    term_loc("B", 2, 3),
107                    or(term_loc("c", 5, 6), term_loc("d", 7, 8)),
108                ),
109            ),
110        );
111    }
112}