Skip to main content

openpql_pql_parser/ast/
expr.rs

1use super::{
2    BinOp, FnCall, Ident, Loc, LocInfo, Num, Spanned, Str, UnaryOp, str,
3};
4
5#[derive(Clone, PartialEq, derive_more::From, derive_more::Debug)]
6pub enum Expr<'i> {
7    #[debug("{_0:?}")]
8    Ident(Ident<'i>),
9    #[debug("{_0:?}")]
10    Str(Str<'i>),
11    #[debug("{_0:?}")]
12    FnCall(FnCall<'i>),
13    #[debug("{_0:?}")]
14    Num(Num),
15    #[debug("{_1:?} {} {_2:?}", _to_op(*_0))]
16    BinOp(BinOp, Box<Self>, Box<Self>),
17    #[debug("{} {_2:?}", _to_unary_op(*_0))]
18    UnaryOp(UnaryOp, Loc, Box<Self>),
19}
20
21#[inline]
22const fn _to_op(op: BinOp) -> &'static str {
23    match op {
24        BinOp::Add => "+",
25        BinOp::Sub => "-",
26        BinOp::Mul => "*",
27        BinOp::Div => "/",
28        BinOp::Eq => "=",
29        BinOp::Ge => "≥",
30        BinOp::Gt => ">",
31        BinOp::Le => "≤",
32        BinOp::Lt => "<",
33        BinOp::And => "and",
34        BinOp::Or => "or",
35    }
36}
37
38#[inline]
39const fn _to_unary_op(op: UnaryOp) -> &'static str {
40    match op {
41        UnaryOp::Not => "not",
42    }
43}
44
45impl Spanned for Expr<'_> {
46    fn loc(&self) -> LocInfo {
47        match self {
48            Expr::Ident(id) => id.loc,
49            Expr::Str(s) => s.loc,
50            Expr::FnCall(fncall) => fncall.loc,
51            Expr::Num(int) => int.loc,
52            Expr::BinOp(_, l, r) => (l.loc().0, r.loc().1),
53            Expr::UnaryOp(_, start, e) => (*start, e.loc().1),
54        }
55    }
56}
57
58impl Expr<'_> {
59    pub(crate) fn binop(op: BinOp, l: Self, r: Self) -> Self {
60        Self::BinOp(op, Box::new(l), Box::new(r))
61    }
62
63    pub(crate) fn unary_op(op: UnaryOp, start: Loc, e: Self) -> Self {
64        Self::UnaryOp(op, start, Box::new(e))
65    }
66}
67
68#[cfg(test)]
69#[cfg_attr(coverage_nightly, coverage(off))]
70mod tests {
71    use super::*;
72    use crate::*;
73
74    fn assert_expr(src: &str, expected: &str) {
75        assert_eq!(format!("{:?}", parse_expr(src).unwrap()), expected);
76    }
77
78    #[test]
79    fn test_binop() {
80        assert_expr("1 + 1", "1 + 1");
81        assert_expr("1 - 1", "1 - 1");
82        assert_expr("1 * 1", "1 * 1");
83        assert_expr("1 / 1", "1 / 1");
84
85        assert_expr("1 = 1", "1 = 1");
86        assert_expr("1 > 1", "1 > 1");
87        assert_expr("1 >= 1", "1 ≥ 1");
88        assert_expr("1 < 1", "1 < 1");
89        assert_expr("1 <= 1", "1 ≤ 1");
90
91        assert_expr("a and b", "a and b");
92        assert_expr("a or b", "a or b");
93        assert_expr("a AND b", "a and b");
94        assert_expr("a OR b", "a or b");
95        assert_expr("a or b and c", "a or b and c");
96        assert_expr("a = 1 and b = 2", "a = 1 and b = 2");
97    }
98
99    #[test]
100    fn test_unary_op() {
101        assert_expr("not a", "not a");
102        assert_expr("NOT a", "not a");
103        assert_expr("not not a", "not not a");
104        assert_expr("not a and b", "not a and b");
105        assert_expr("a and not b", "a and not b");
106        assert_expr("not a = 1", "not a = 1");
107    }
108
109    #[test]
110    fn test_expr() {
111        assert_expr("id", "id");
112        assert_expr("'str'", "\"str\"");
113        assert_expr("sin(x)", "sin(x)");
114    }
115
116    fn assert_loc(src: &str, start: Loc, end: Loc) {
117        assert_eq!(parse_expr(src).unwrap().loc(), (start, end));
118    }
119
120    #[test]
121    fn test_loc() {
122        assert_loc("a", 0, 1);
123        assert_loc("'a'", 0, 3);
124        assert_loc("sin(x)", 0, 6);
125        assert_loc("10", 0, 2);
126        assert_loc("1 >= 3", 0, 6);
127        assert_loc("not a", 0, 5);
128    }
129
130    #[test]
131    fn test_debug() {
132        fn assert_dbg(s: &str, expected: &str) {
133            assert_eq!(format!("{:?}", parse_expr(s).unwrap()), expected);
134        }
135
136        assert_dbg("ident", "ident");
137
138        assert_dbg("'string'", "\"string\"");
139
140        assert_dbg("fncall(v1, v2)", "fncall(v1,v2)");
141
142        assert_dbg("100", "100");
143        assert_dbg("3.14", "3.14");
144
145        assert_dbg("1 = 1", "1 = 1");
146        assert_dbg("1 >= 1", "1 ≥ 1");
147    }
148}