openpql-range-parser 0.1.5

Poker Range Notation Parser
Documentation
use super::{LocInfo, Term};

/// Parsed range expression tree.
#[derive(PartialEq, Eq, Debug)]
pub enum Expr {
    /// Exclusion `A!B`.
    Not(Box<Self>, Box<Self>),
    /// Intersection `A:B`.
    And(Box<Self>, Box<Self>),
    /// Union `A,B`.
    Or(Box<Self>, Box<Self>),
    /// Leaf term with its source span.
    Term(Term, LocInfo),
}

impl From<(Term, LocInfo)> for Expr {
    fn from((t, loc): (Term, LocInfo)) -> Self {
        Self::Term(t, loc)
    }
}

#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
    use super::*;
    use crate::*;

    fn assert_expr(s: &str, expected: Expr) {
        assert_eq!(
            *parse_expr(false, s).unwrap(),
            expected,
            "{s} != {expected:?}"
        );
    }

    fn term_loc(s: &str, a: Loc, b: Loc) -> (Term, LocInfo) {
        (parse_term(s).unwrap(), (a, b))
    }

    fn binop<S, T>(l: S, r: T, f: fn(Box<Expr>, Box<Expr>) -> Expr) -> Expr
    where
        Expr: From<S> + From<T>,
    {
        f(Box::new(Expr::from(l)), Box::new(Expr::from(r)))
    }

    fn not<S, T>(l: S, r: T) -> Expr
    where
        Expr: From<S> + From<T>,
    {
        binop(l, r, Expr::Not)
    }

    fn and<S, T>(l: S, r: T) -> Expr
    where
        Expr: From<S> + From<T>,
    {
        binop(l, r, Expr::And)
    }

    fn or<S, T>(l: S, r: T) -> Expr
    where
        Expr: From<S> + From<T>,
    {
        binop(l, r, Expr::Or)
    }

    #[test]
    fn test_expr_term() {
        assert_expr("AsA", term_loc("AsA", 0, 3).into());
    }

    #[test]
    fn test_expr_and() {
        assert_expr("AsA:ss", and(term_loc("AsA", 0, 3), term_loc("ss", 4, 6)));
    }

    #[test]
    fn test_expr_or() {
        assert_expr("AsA,ss", or(term_loc("AsA", 0, 3), term_loc("ss", 4, 6)));
    }

    #[test]
    fn test_expr_not() {
        assert_expr("AsA!ss", not(term_loc("AsA", 0, 3), term_loc("ss", 4, 6)));
    }

    #[test]
    fn test_expr_precedence() {
        assert_expr(
            "A:B!c,d",
            or(
                and(
                    term_loc("A", 0, 1),
                    not(term_loc("B", 2, 3), term_loc("c", 4, 5)),
                ),
                term_loc("d", 6, 7),
            ),
        );

        assert_expr(
            "A:B!(c,d)",
            and(
                term_loc("A", 0, 1),
                not(
                    term_loc("B", 2, 3),
                    or(term_loc("c", 5, 6), term_loc("d", 7, 8)),
                ),
            ),
        );
    }
}