openpql-pql-parser 0.1.0

A parser implementation for Poker Query Language (PQL)
Documentation
use super::{BinOp, FnCall, Ident, LocInfo, Num, Str, str};

#[derive(Clone, PartialEq, derive_more::From, derive_more::Debug)]
pub enum Expr<'i> {
    #[debug("{_0:?}")]
    Ident(Ident<'i>),
    #[debug("{_0:?}")]
    Str(Str<'i>),
    #[debug("{_0:?}")]
    FnCall(FnCall<'i>),
    #[debug("{_0:?}")]
    Num(Num),
    #[debug("{_1:?} {} {_2:?}", _to_op(*_0))]
    BinOp(BinOp, Box<Self>, Box<Self>),
}

#[inline]
const fn _to_op(op: BinOp) -> &'static str {
    match op {
        BinOp::Add => "+",
        BinOp::Sub => "-",
        BinOp::Mul => "*",
        BinOp::Div => "/",
        BinOp::Eq => "=",
        BinOp::Ge => "",
        BinOp::Gt => ">",
        BinOp::Le => "",
        BinOp::Lt => "<",
    }
}

impl Expr<'_> {
    pub const fn loc(&self) -> LocInfo {
        match self {
            Expr::Ident(id) => id.loc,
            Expr::Str(s) => s.loc,
            Expr::FnCall(fncall) => fncall.loc,
            Expr::Num(int) => int.loc,
            Expr::BinOp(_, l, r) => (l.loc().0, r.loc().1),
        }
    }

    pub(crate) fn binop(op: BinOp, l: Self, r: Self) -> Self {
        Self::BinOp(op, Box::new(l), Box::new(r))
    }
}

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

    fn assert_expr(src: &str, expected: &str) {
        assert_eq!(format!("{:?}", parse_expr(src).unwrap()), expected);
    }

    #[test]
    fn test_binop() {
        assert_expr("1 + 1", "1 + 1");
        assert_expr("1 - 1", "1 - 1");
        assert_expr("1 * 1", "1 * 1");
        assert_expr("1 / 1", "1 / 1");

        assert_expr("1 = 1", "1 = 1");
        assert_expr("1 > 1", "1 > 1");
        assert_expr("1 >= 1", "1 ≥ 1");
        assert_expr("1 < 1", "1 < 1");
        assert_expr("1 <= 1", "1 ≤ 1");
    }

    #[test]
    fn test_expr() {
        assert_expr("id", "id");
        assert_expr("'str'", "\"str\"");
        assert_expr("sin(x)", "sin(x)");
    }

    fn assert_loc(src: &str, start: Loc, end: Loc) {
        assert_eq!(parse_expr(src).unwrap().loc(), (start, end));
    }

    #[test]
    fn test_loc() {
        assert_loc("a", 0, 1);
        assert_loc("'a'", 0, 3);
        assert_loc("sin(x)", 0, 6);
        assert_loc("10", 0, 2);
        assert_loc("1 >= 3", 0, 6);
    }

    #[test]
    fn test_debug() {
        fn assert_dbg(s: &str, expected: &str) {
            assert_eq!(format!("{:?}", parse_expr(s).unwrap()), expected);
        }

        assert_dbg("ident", "ident");

        assert_dbg("'string'", "\"string\"");

        assert_dbg("fncall(v1, v2)", "fncall(v1,v2)");

        assert_dbg("100", "100");
        assert_dbg("3.14", "3.14");

        assert_dbg("1 = 1", "1 = 1");
        assert_dbg("1 >= 1", "1 ≥ 1");
    }
}