rsdiff_core/ops/
expr.rs

1/*
2    Appellation: expr <mod>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use 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}