1use crate::id::IndexId;
6use crate::ops::{BinaryOp, NaryOp, TernaryOp, UnaryOp};
7use crate::prelude::AnyBox;
8use paste::paste;
9use strum::EnumIs;
10
11pub(crate) type BoxExpr<K = usize, V = AnyBox> = Box<Expr<K, V>>;
12
13#[derive(Clone, Debug, EnumIs, Eq, Hash, Ord, PartialEq, PartialOrd)]
14pub enum Expr<K = usize, V = AnyBox> {
15 Binary(ExprBinary<K, V>),
16 Nary(ExprNary<K, V>),
17 Ternary(ExprTernary<K, V>),
18 Unary(ExprUnary<K, V>),
19 Constant(V),
20 Variable { id: IndexId<K>, value: V },
21}
22
23impl<K, V> Expr<K, V> {
24 pub fn binary(lhs: Expr<K, V>, rhs: Expr<K, V>, op: BinaryOp) -> Self {
25 Self::Binary(ExprBinary::new(lhs, rhs, op))
26 }
27
28 pub fn constant(value: V) -> Self {
29 Self::Constant(value)
30 }
31
32 pub fn nary(args: impl IntoIterator<Item = Expr<K, V>>, op: NaryOp) -> Self {
33 Self::Nary(ExprNary::new(args, op))
34 }
35
36 pub fn ternary(x: Expr<K, V>, y: Expr<K, V>, z: Expr<K, V>, op: TernaryOp) -> Self {
37 Self::Ternary(ExprTernary::new(x, y, z, op))
38 }
39
40 pub fn unary(recv: Expr<K, V>, op: UnaryOp) -> Self {
41 Self::Unary(ExprUnary::new(recv, op))
42 }
43
44 pub fn variable(idx: K, value: V) -> Self {
45 Self::Variable {
46 id: IndexId::from_index(idx),
47 value,
48 }
49 }
50
51 pub fn boxed(self) -> BoxExpr<K, V> {
52 Box::new(self)
53 }
54}
55
56macro_rules! expr_variant {
57 ($variant:ident<$op:ty>($($param:ident),*)) => {
58 #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
59 pub struct $variant<K = usize, V = AnyBox> {
60 op: $op,
61 $($param: Box<Expr<K, V>>),*
62 }
63
64 impl<K, V> $variant<K, V> {
65 pub fn new($($param: Expr<K, V>,)* op: $op,) -> Self {
66 Self {
67 op,
68 $($param: Box::new($param)),*
69 }
70 }
71
72 pub fn op(&self) -> $op {
73 self.op
74 }
75
76 pub fn op_mut(&mut self) -> &mut $op {
77 &mut self.op
78 }
79
80 $(
81 pub fn $param(&self) -> &Expr<K, V> {
82 &self.$param
83 }
84 )*
85
86 paste! {
87 $(
88 pub fn [<$param _mut>](&mut self) -> &mut Expr<K, V> {
89 &mut self.$param
90 }
91 )*
92 }
93 }
94 };
95
96}
97
98expr_variant!(ExprBinary<BinaryOp>(lhs, rhs));
99expr_variant!(ExprTernary<TernaryOp>(x, y, z));
100expr_variant!(ExprUnary<UnaryOp>(recv));
101
102#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
103pub struct ExprNary<K = usize, V = AnyBox> {
104 args: Vec<Box<Expr<K, V>>>,
105 op: NaryOp,
106}
107
108impl<K, V> ExprNary<K, V> {
109 pub fn new(args: impl IntoIterator<Item = Expr<K, V>>, op: NaryOp) -> Self {
110 Self {
111 args: Vec::from_iter(args.into_iter().map(|i| i.boxed())),
112 op,
113 }
114 }
115
116 pub fn as_slice(&self) -> &[Box<Expr<K, V>>] {
117 &self.args
118 }
119
120 pub fn as_mut_slice(&mut self) -> &mut [Box<Expr<K, V>>] {
121 &mut self.args
122 }
123
124 pub fn args(&self) -> &Vec<Box<Expr<K, V>>> {
125 &self.args
126 }
127
128 pub fn args_mut(&mut self) -> &mut Vec<Box<Expr<K, V>>> {
129 &mut self.args
130 }
131
132 pub fn op(&self) -> NaryOp {
133 self.op
134 }
135
136 pub fn op_mut(&mut self) -> &mut NaryOp {
137 &mut self.op
138 }
139}