tytanic_filter/ast/
expr.rs

1use std::sync::Arc;
2
3use pest::iterators::Pair;
4use pest::pratt_parser::PrattParser;
5
6use super::Atom;
7use super::Error;
8use super::Func;
9use super::Id;
10use super::Num;
11use super::Pat;
12use super::Rule;
13use super::Str;
14use crate::eval;
15use crate::eval::Context;
16use crate::eval::Eval;
17use crate::eval::Set;
18use crate::eval::Test;
19use crate::eval::Value;
20
21/// An unary prefix operator.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub enum PrefixOp {
24    /// The negation operator. Matches the symbols `not` and `!`.
25    Not,
26}
27
28/// A binary infix operator.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub enum InfixOp {
31    /// The union/or operator. Matches the symbols `or` and `|`.
32    Union,
33
34    /// The intersection/and operator. Matches the symbols `and` and `&`.
35    Inter,
36
37    /// The difference operator. Matches the symbols `diff` and `~`.
38    Diff,
39
40    /// The symmetric difference/xor operator. Matches the symbols `xor` and
41    /// `^`.
42    SymDiff,
43}
44
45/// An expression node.
46#[derive(Debug, Clone, PartialEq, Eq, Hash)]
47pub enum Expr {
48    /// An expression atom.
49    Atom(Atom),
50
51    /// A function call expression.
52    Func(Func),
53
54    /// A prefix expression.
55    Prefix {
56        /// The unary prefix operator.
57        op: PrefixOp,
58
59        /// The inner expression.
60        expr: Arc<Expr>,
61    },
62
63    /// An infix expression.
64    Infix {
65        /// The binary infix operator.
66        op: InfixOp,
67
68        /// The left-hand side of this binary expression.
69        lhs: Arc<Expr>,
70
71        /// The right-hand side of this binary expression.
72        rhs: Arc<Expr>,
73    },
74}
75
76// TODO(tinger): Flatten intersection and union chains.
77impl<T: Test> Eval<T> for Expr {
78    fn eval(&self, ctx: &Context<T>) -> Result<Value<T>, eval::Error> {
79        match self {
80            Self::Atom(atom) => atom.eval(ctx),
81            Self::Func(func) => func.eval(ctx),
82            Self::Prefix { op, expr } => {
83                // Unary prefix operator is only valid for test sets.
84                let set: Set<T> = expr.eval(ctx)?.expect_type()?;
85
86                Ok(Value::Set(match op {
87                    PrefixOp::Not => Set::expr_comp(set),
88                }))
89            }
90            Self::Infix { op, lhs, rhs } => {
91                // Binary infix operator is only valid for test sets.
92                let lhs: Set<T> = lhs.eval(ctx)?.expect_type()?;
93                let rhs: Set<T> = rhs.eval(ctx)?.expect_type()?;
94
95                Ok(Value::Set(match op {
96                    InfixOp::Union => Set::expr_union(lhs, rhs, []),
97                    InfixOp::Inter => Set::expr_inter(lhs, rhs, []),
98                    InfixOp::Diff => Set::expr_diff(lhs, rhs),
99                    InfixOp::SymDiff => Set::expr_sym_diff(lhs, rhs),
100                }))
101            }
102        }
103    }
104}
105
106impl Expr {
107    pub(super) fn parse(pair: Pair<'_, Rule>, pratt: &PrattParser<Rule>) -> Result<Expr, Error> {
108        pratt
109            .map_primary(|primary| {
110                Ok(match primary.as_rule() {
111                    Rule::id => Expr::Atom(Atom::Id(Id::parse(primary)?)),
112                    Rule::pat_inner => Expr::Atom(Atom::Pat(Pat::parse(primary)?)),
113                    Rule::str_single | Rule::str_double => {
114                        Expr::Atom(Atom::Str(Str::parse(primary)?))
115                    }
116                    Rule::num_inner => Expr::Atom(Atom::Num(Num::parse(primary)?)),
117                    Rule::func => Expr::Func(Func::parse(primary, pratt)?),
118                    Rule::expr => Self::parse(primary, pratt)?,
119                    x => unreachable!("unhandled primary expression {x:?}"),
120                })
121            })
122            .map_prefix(|op, expr| match op.as_rule().to_prefix() {
123                Some(op) => Ok(Expr::Prefix {
124                    op,
125                    expr: Arc::new(expr?),
126                }),
127                None => unreachable!("unhandled prefix operator {:?}", op.as_rule()),
128            })
129            .map_infix(|lhs, op, rhs| match op.as_rule().to_infix() {
130                Some(op) => Ok(Expr::Infix {
131                    op,
132                    lhs: Arc::new(lhs?),
133                    rhs: Arc::new(rhs?),
134                }),
135                None => unreachable!("unhandled infix operator {:?}", op.as_rule()),
136            })
137            .parse(pair.into_inner())
138    }
139}