1use std::sync::Arc;
2
3use pest::iterators::Pair;
4use pest::pratt_parser::PrattParser;
5
6use super::{Atom, Error, Func, Id, Num, Pat, Rule, Str};
7use crate::eval::{self, Context, Eval, Set, Test, Value};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub enum PrefixOp {
12 Not,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub enum InfixOp {
19 Union,
21
22 Inter,
24
25 Diff,
27
28 SymDiff,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub enum Expr {
36 Atom(Atom),
38
39 Func(Func),
41
42 Prefix {
44 op: PrefixOp,
46
47 expr: Arc<Expr>,
49 },
50
51 Infix {
53 op: InfixOp,
55
56 lhs: Arc<Expr>,
58
59 rhs: Arc<Expr>,
61 },
62}
63
64impl<T: Test> Eval<T> for Expr {
66 fn eval(&self, ctx: &Context<T>) -> Result<Value<T>, eval::Error> {
67 match self {
68 Self::Atom(atom) => atom.eval(ctx),
69 Self::Func(func) => func.eval(ctx),
70 Self::Prefix { op, expr } => {
71 let set: Set<T> = expr.eval(ctx)?.expect_type()?;
73
74 Ok(Value::Set(match op {
75 PrefixOp::Not => Set::expr_comp(set),
76 }))
77 }
78 Self::Infix { op, lhs, rhs } => {
79 let lhs: Set<T> = lhs.eval(ctx)?.expect_type()?;
81 let rhs: Set<T> = rhs.eval(ctx)?.expect_type()?;
82
83 Ok(Value::Set(match op {
84 InfixOp::Union => Set::expr_union(lhs, rhs, []),
85 InfixOp::Inter => Set::expr_inter(lhs, rhs, []),
86 InfixOp::Diff => Set::expr_diff(lhs, rhs),
87 InfixOp::SymDiff => Set::expr_sym_diff(lhs, rhs),
88 }))
89 }
90 }
91 }
92}
93
94impl Expr {
95 pub(super) fn parse(pair: Pair<'_, Rule>, pratt: &PrattParser<Rule>) -> Result<Expr, Error> {
96 pratt
97 .map_primary(|primary| {
98 Ok(match primary.as_rule() {
99 Rule::id => Expr::Atom(Atom::Id(Id::parse(primary)?)),
100 Rule::pat_inner => Expr::Atom(Atom::Pat(Pat::parse(primary)?)),
101 Rule::str_single | Rule::str_double => {
102 Expr::Atom(Atom::Str(Str::parse(primary)?))
103 }
104 Rule::num_inner => Expr::Atom(Atom::Num(Num::parse(primary)?)),
105 Rule::func => Expr::Func(Func::parse(primary, pratt)?),
106 Rule::expr => Self::parse(primary, pratt)?,
107 x => unreachable!("unhandled primary expression {x:?}"),
108 })
109 })
110 .map_prefix(|op, expr| match op.as_rule().to_prefix() {
111 Some(op) => Ok(Expr::Prefix {
112 op,
113 expr: Arc::new(expr?),
114 }),
115 None => unreachable!("unhandled prefix operator {:?}", op.as_rule()),
116 })
117 .map_infix(|lhs, op, rhs| match op.as_rule().to_infix() {
118 Some(op) => Ok(Expr::Infix {
119 op,
120 lhs: Arc::new(lhs?),
121 rhs: Arc::new(rhs?),
122 }),
123 None => unreachable!("unhandled infix operator {:?}", op.as_rule()),
124 })
125 .parse(pair.into_inner())
126 }
127}