z3/
ops.rs

1use crate::ast::{Bool, Float, IntoAst};
2use std::iter::Product;
3use std::iter::Sum;
4use std::ops::{
5    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
6    Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Sub, SubAssign,
7};
8
9use crate::ast::{BV, Int, Real};
10
11macro_rules! impl_unary_op_raw {
12    ($ty:ty, $output:ty, $base_trait:ident, $base_fn:ident, $function:ident) => {
13        impl $base_trait for $ty {
14            type Output = $output;
15
16            fn $base_fn(self) -> Self::Output {
17                (&self as &$output).$function()
18            }
19        }
20    };
21}
22
23macro_rules! impl_unary_op {
24    ($ty:ident::$function:ident = $base_trait:ident::$base_fn:ident) => {
25        impl_unary_op_raw!($ty, $ty, $base_trait, $base_fn, $function);
26        impl_unary_op_raw!(&$ty, $ty, $base_trait, $base_fn, $function);
27    };
28}
29
30impl_unary_op!(BV::bvnot = Not::not);
31impl_unary_op!(BV::bvneg = Neg::neg);
32
33macro_rules! impl_bin_trait {
34    ($t:ident::$op:ident = $tr:ident::$trop:ident) => {
35        impl<T: IntoAst<$t>> $tr<T> for $t {
36            type Output = $t;
37            fn $trop(self, rhs: T) -> Self::Output {
38                let rhs = rhs.into_ast(&self);
39                <$t>::$op(&self, rhs)
40            }
41        }
42
43        impl<T: IntoAst<$t>> $tr<T> for &$t {
44            type Output = $t;
45            fn $trop(self, rhs: T) -> Self::Output {
46                let rhs = rhs.into_ast(&self);
47                <$t>::$op(&self, rhs)
48            }
49        }
50    };
51}
52
53macro_rules! impl_bin_assign_trait {
54    ($t:ident::$op:ident = $tr:ident::$trop:ident) => {
55        impl<T: IntoAst<$t>> $tr<T> for $t {
56            fn $trop(&mut self, rhs: T) {
57                let res = (self as &mut $t).clone().$op(rhs);
58                *self = res
59            }
60        }
61    };
62}
63
64macro_rules! impl_var_trait {
65    ($t:ident::$op:ident = $tr:ident::$trop:ident) => {
66        impl<T: IntoAst<$t>> $tr<T> for $t {
67            type Output = $t;
68            fn $trop(self, rhs: T) -> Self::Output {
69                let rhs = rhs.into_ast(&self);
70                <$t>::$op(&[self.clone(), rhs])
71            }
72        }
73
74        impl<T: IntoAst<$t>> $tr<T> for &$t {
75            type Output = $t;
76            fn $trop(self, rhs: T) -> Self::Output {
77                let rhs = rhs.into_ast(&self);
78                <$t>::$op(&[self.clone(), rhs])
79            }
80        }
81    };
82}
83
84impl_var_trait!(Bool::and = BitAnd::bitand);
85impl_var_trait!(Bool::or = BitOr::bitor);
86impl_bin_trait!(Bool::xor = BitXor::bitxor);
87
88impl_bin_assign_trait!(Bool::bitand = BitAndAssign::bitand_assign);
89impl_bin_assign_trait!(Bool::bitor = BitOrAssign::bitor_assign);
90impl_bin_assign_trait!(Bool::bitxor = BitXorAssign::bitxor_assign);
91
92impl_bin_trait!(BV::bvadd = Add::add);
93impl_bin_trait!(BV::bvsub = Sub::sub);
94impl_bin_trait!(BV::bvmul = Mul::mul);
95impl_bin_trait!(BV::bvand = BitAnd::bitand);
96impl_bin_trait!(BV::bvor = BitOr::bitor);
97impl_bin_trait!(BV::bvxor = BitXor::bitxor);
98impl_bin_trait!(BV::bvshl = Shl::shl);
99
100impl_bin_assign_trait!(BV::bvadd = AddAssign::add_assign);
101impl_bin_assign_trait!(BV::bvsub = SubAssign::sub_assign);
102impl_bin_assign_trait!(BV::bvmul = MulAssign::mul_assign);
103impl_bin_assign_trait!(BV::bvand = BitAndAssign::bitand_assign);
104impl_bin_assign_trait!(BV::bvor = BitOrAssign::bitor_assign);
105impl_bin_assign_trait!(BV::bvxor = BitXorAssign::bitxor_assign);
106impl_bin_assign_trait!(BV::bvshl = ShlAssign::shl_assign);
107
108impl_unary_op!(Int::unary_minus = Neg::neg);
109
110impl_var_trait!(Int::add = Add::add);
111impl_var_trait!(Int::sub = Sub::sub);
112impl_var_trait!(Int::mul = Mul::mul);
113impl_bin_trait!(Int::div = Div::div);
114impl_bin_trait!(Int::rem = Rem::rem);
115
116impl_bin_assign_trait!(Int::add = AddAssign::add_assign);
117impl_bin_assign_trait!(Int::sub = SubAssign::sub_assign);
118impl_bin_assign_trait!(Int::mul = MulAssign::mul_assign);
119impl_bin_assign_trait!(Int::div = DivAssign::div_assign);
120impl_bin_assign_trait!(Int::rem = RemAssign::rem_assign);
121
122impl_var_trait!(Real::add = Add::add);
123impl_var_trait!(Real::sub = Sub::sub);
124impl_var_trait!(Real::mul = Mul::mul);
125impl_bin_trait!(Real::div = Div::div);
126impl_unary_op!(Real::unary_minus = Neg::neg);
127
128impl_bin_assign_trait!(Real::add = AddAssign::add_assign);
129impl_bin_assign_trait!(Real::sub = SubAssign::sub_assign);
130impl_bin_assign_trait!(Real::mul = MulAssign::mul_assign);
131impl_bin_assign_trait!(Real::div = DivAssign::div_assign);
132
133// implementations for Real
134//
135// // // implementations for Float
136impl_unary_op!(Float::unary_neg = Neg::neg);
137//
138// // implementations for Bool
139impl_unary_op!(Bool::not = Not::not);
140
141// Impl bin ops for concrete types on the left-hand-side that people
142// might want to use
143// Note that this is not necessary when an Ast is on the left hand
144// side because it is covered by a blanket impl of `IntoAst`. This
145// does not work for the IntoAst being on the LHS because of the orphan
146// rule
147macro_rules! impl_trait_number_types {
148    ($Z3ty:ty, $tr:ident::$op:ident, [$($num:ty),+]) => {
149        $(
150        impl_trait_number_types!($Z3ty, $tr::$op, $num);
151        )+
152    };
153    ($Z3ty:ty, $tr:ident::$op:ident, $num:ty) => {
154        impl $tr<$Z3ty> for $num {
155            type Output = $Z3ty;
156            fn $op(self, rhs: $Z3ty) -> Self::Output {
157                let lhs = self.into_ast(&rhs);
158                lhs.$op(&rhs)
159            }
160        }
161
162        impl<'a> $tr<&'a $Z3ty> for $num {
163            type Output = $Z3ty;
164            fn $op(self, rhs: &'a $Z3ty) -> Self::Output {
165                let lhs = self.into_ast(rhs);
166                lhs.$op(rhs)
167            }
168        }
169    };
170}
171
172impl_trait_number_types!(Int, Add::add, [u8, i8, u16, i16, u32, i32, u64, i64]);
173impl_trait_number_types!(Int, Sub::sub, [u8, i8, u16, i16, u32, i32, u64, i64]);
174impl_trait_number_types!(Int, Mul::mul, [u8, i8, u16, i16, u32, i32, u64, i64]);
175impl_trait_number_types!(Int, Div::div, [u8, i8, u16, i16, u32, i32, u64, i64]);
176
177impl_trait_number_types!(BV, Add::add, [u8, i8, u16, i16, u32, i32, u64, i64]);
178impl_trait_number_types!(BV, Sub::sub, [u8, i8, u16, i16, u32, i32, u64, i64]);
179impl_trait_number_types!(BV, Mul::mul, [u8, i8, u16, i16, u32, i32, u64, i64]);
180impl_trait_number_types!(BV, BitXor::bitxor, [u8, i8, u16, i16, u32, i32, u64, i64]);
181impl_trait_number_types!(BV, BitAnd::bitand, [u8, i8, u16, i16, u32, i32, u64, i64]);
182impl_trait_number_types!(BV, BitOr::bitor, [u8, i8, u16, i16, u32, i32, u64, i64]);
183
184macro_rules! integer_sum_product {
185    ($zero:expr, $one:expr, $($a:ty)*) => ($(
186        impl Sum for $a {
187            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
188                iter.reduce(
189                    |a, b| a + b,
190                ).unwrap_or($zero)
191            }
192        }
193
194        impl Product for $a {
195            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
196                iter.reduce(
197                    |a, b| a * b,
198                ).unwrap_or($one)
199            }
200        }
201
202        impl<'a> Sum<&'a $a> for $a {
203            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
204                iter.cloned().reduce(
205                    |a, b| a + b,
206                ).unwrap_or($zero)
207            }
208        }
209
210        impl<'a> Product<&'a $a> for $a {
211            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
212                iter.cloned().reduce(
213                    |a, b| a * b,
214                ).unwrap_or($one)
215            }
216        }
217    )*);
218}
219
220integer_sum_product!(Int::from_u64(0), Int::from_u64(1), Int);
221integer_sum_product!(Real::from_rational(0, 1), Real::from_rational(1, 1), Real);