Skip to main content

scan_core/
grammar.rs

1//! The language used by PGs and CSs.
2//!
3//! The type [`Expression<V>`] encodes the used language,
4//! where `V` is the type parameter of variables.
5//! The language features base types and product types,
6//! Boolean logic and basic arithmetic expressions.
7
8mod boolean;
9mod float;
10mod integer;
11mod natural;
12
13use get_size2::GetSize;
14use rand::{Rng, rngs::SmallRng};
15use std::{
16    hash::Hash,
17    ops::{Add, BitAnd, BitOr, Div, Mul, Neg, Not, Rem},
18};
19use thiserror::Error;
20
21pub use boolean::*;
22pub use float::*;
23pub use integer::*;
24pub use natural::*;
25
26/// The error type for operations with [`Type`].
27#[derive(Debug, Clone, Copy, Error)]
28pub enum TypeError {
29    /// Types that should be matching are not,
30    /// or are not compatible with each other.
31    #[error("type mismatch")]
32    TypeMismatch,
33    /// The variable's type is unknown.
34    #[error("the type of variable is unknown")]
35    UnknownVar,
36    /// Probability violates some constraint.
37    #[error("the probability violates some constraint")]
38    BadProbability,
39}
40
41/// The types supported by the language internally used by PGs and CSs.
42#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, GetSize)]
43pub enum Type {
44    /// Boolean type.
45    Boolean,
46    /// Natural (unsigned) numerical type.
47    Natural,
48    /// Integer numerical type.
49    Integer,
50    /// Floating-point numerical type.
51    Float,
52}
53
54impl Type {
55    /// The default value for a given type.
56    /// Used to initialize variables.
57    pub fn default_value(self) -> Val {
58        match self {
59            Type::Boolean => Val::Boolean(false),
60            Type::Natural => Val::Natural(0),
61            Type::Integer => Val::Integer(0),
62            Type::Float => Val::Float(0.0),
63        }
64    }
65}
66
67/// Possible values for each [`Type`].
68#[derive(Debug, Clone, Copy, PartialEq, GetSize)]
69pub enum Val {
70    /// Boolean values.
71    Boolean(bool),
72    /// Natural (unsigned) values.
73    Natural(Natural),
74    /// Integer values.
75    Integer(Integer),
76    /// Floating-point values.
77    Float(Float),
78}
79
80impl Val {
81    /// Returns the [`Type`] of the value.
82    pub fn r#type(self) -> Type {
83        match self {
84            Val::Boolean(_) => Type::Boolean,
85            Val::Natural(_) => Type::Natural,
86            Val::Integer(_) => Type::Integer,
87            Val::Float(_) => Type::Float,
88        }
89    }
90}
91
92impl From<bool> for Val {
93    fn from(value: bool) -> Self {
94        Val::Boolean(value)
95    }
96}
97
98impl From<Natural> for Val {
99    fn from(value: Natural) -> Self {
100        Val::Natural(value)
101    }
102}
103
104impl From<Integer> for Val {
105    fn from(value: Integer) -> Self {
106        Val::Integer(value)
107    }
108}
109
110impl From<Float> for Val {
111    fn from(value: Float) -> Self {
112        Val::Float(value)
113    }
114}
115
116/// Expressions for the language internally used by PGs and CSs.
117///
118/// [`Expression<V>`] encodes the language in which `V` is the type of variables.
119///
120/// Note that not all expressions that can be formed are well-typed.
121#[derive(Debug, Clone, GetSize)]
122pub enum Expression<V>
123where
124    V: Clone,
125{
126    /// Expression of Boolean type.
127    Boolean(BooleanExpr<V>),
128    /// Expression of Natural type (unsigned integers).
129    Natural(NaturalExpr<V>),
130    /// Expression of Integer type.
131    Integer(IntegerExpr<V>),
132    /// Expression of Float type.
133    Float(FloatExpr<V>),
134}
135
136impl<V> From<Val> for Expression<V>
137where
138    V: Clone,
139{
140    fn from(value: Val) -> Self {
141        match value {
142            Val::Boolean(b) => Expression::Boolean(BooleanExpr::Const(b)),
143            Val::Natural(nat) => Expression::Natural(NaturalExpr::Const(nat)),
144            Val::Integer(int) => Expression::Integer(IntegerExpr::Const(int)),
145            Val::Float(float) => Expression::Float(FloatExpr::Const(float)),
146        }
147    }
148}
149
150impl<V> From<bool> for Expression<V>
151where
152    V: Clone,
153{
154    fn from(value: bool) -> Self {
155        Expression::Boolean(BooleanExpr::from(value))
156    }
157}
158
159impl<V> From<Natural> for Expression<V>
160where
161    V: Clone,
162{
163    fn from(value: Natural) -> Self {
164        Expression::Natural(NaturalExpr::from(value))
165    }
166}
167
168impl<V> From<Integer> for Expression<V>
169where
170    V: Clone,
171{
172    fn from(value: Integer) -> Self {
173        Expression::Integer(IntegerExpr::from(value))
174    }
175}
176
177impl<V> From<Float> for Expression<V>
178where
179    V: Clone,
180{
181    fn from(value: Float) -> Self {
182        Expression::Float(FloatExpr::from(value))
183    }
184}
185
186impl<V> From<(V, Type)> for Expression<V>
187where
188    V: Copy,
189{
190    fn from((var, r#type): (V, Type)) -> Self {
191        Expression::from_var(var, r#type)
192    }
193}
194
195impl<V> Expression<V>
196where
197    V: Copy,
198{
199    /// Computes the type of an expression.
200    ///
201    /// Fails if the expression is badly typed,
202    /// e.g., if variables in it have type incompatible with the expression.
203    pub fn r#type(&self) -> Type {
204        match self {
205            Expression::Boolean(_) => Type::Boolean,
206            Expression::Natural(_) => Type::Natural,
207            Expression::Integer(_) => Type::Integer,
208            Expression::Float(_) => Type::Float,
209        }
210    }
211
212    /// Evaluates the expression with the given variable assignments and provided RNG.
213    ///
214    /// Will assume the expression (with the variable assignment) is well-typed,
215    /// and may panic if producing an unexpected type.
216    pub fn eval<R: Rng>(&self, vars: &dyn Fn(V) -> Val, rng: Option<&mut R>) -> Val {
217        match self {
218            Expression::Boolean(boolean_expr) => Val::Boolean(boolean_expr.eval(vars, rng)),
219            Expression::Natural(natural_expr) => Val::Natural(natural_expr.eval(vars, rng)),
220            Expression::Integer(integer_expr) => Val::Integer(integer_expr.eval(vars, rng)),
221            Expression::Float(float_expr) => Val::Float(float_expr.eval(vars, rng)),
222        }
223    }
224
225    /// Evaluates the expression with the given variable assignments.
226    ///
227    /// Will assume the expression (with the variable assignment) is well-typed,
228    /// and may panic if producing an unexpected type.
229    pub fn eval_deterministic(&self, vars: &dyn Fn(V) -> Val) -> Val {
230        match self {
231            Expression::Boolean(boolean_expr) => {
232                Val::Boolean(boolean_expr.eval::<SmallRng>(vars, None))
233            }
234            Expression::Natural(natural_expr) => {
235                Val::Natural(natural_expr.eval::<SmallRng>(vars, None))
236            }
237            Expression::Integer(integer_expr) => {
238                Val::Integer(integer_expr.eval::<SmallRng>(vars, None))
239            }
240            Expression::Float(float_expr) => Val::Float(float_expr.eval::<SmallRng>(vars, None)),
241        }
242    }
243
244    /// Evals a constant expression.
245    /// Returns an error if expression contains variables.
246    pub fn is_constant(&self) -> bool {
247        match self {
248            Expression::Boolean(boolean_expr) => boolean_expr.is_constant(),
249            Expression::Natural(natural_expr) => natural_expr.is_constant(),
250            Expression::Integer(integer_expr) => integer_expr.is_constant(),
251            Expression::Float(float_expr) => float_expr.is_constant(),
252        }
253    }
254
255    /// Evals a constant expression.
256    /// Returns an error if expression contains variables.
257    pub fn eval_constant(&self) -> Result<Val, TypeError> {
258        if self.is_constant() {
259            Ok(self.eval::<rand::rngs::SmallRng>(&|_| panic!("no vars"), None))
260        } else {
261            Err(TypeError::UnknownVar)
262        }
263    }
264
265    pub(crate) fn map<W: Clone>(self, map: &dyn Fn(V) -> W) -> Expression<W> {
266        match self {
267            Expression::Boolean(boolean_expr) => Expression::Boolean(boolean_expr.map(map)),
268            Expression::Natural(natural_expr) => Expression::Natural(natural_expr.map(map)),
269            Expression::Integer(integer_expr) => Expression::Integer(integer_expr.map(map)),
270            Expression::Float(float_expr) => Expression::Float(float_expr.map(map)),
271        }
272    }
273
274    pub(crate) fn context(&self, vars: &dyn Fn(V) -> Option<Type>) -> Result<(), TypeError> {
275        match self {
276            Expression::Boolean(boolean_expr) => boolean_expr.context(vars),
277            Expression::Natural(natural_expr) => natural_expr.context(vars),
278            Expression::Integer(integer_expr) => integer_expr.context(vars),
279            Expression::Float(float_expr) => float_expr.context(vars),
280        }
281    }
282
283    /// Creates an `[Expression]` out of a variable and the type of such variable.
284    pub fn from_var(var: V, r#type: Type) -> Self {
285        match r#type {
286            Type::Boolean => Expression::Boolean(BooleanExpr::Var(var)),
287            Type::Natural => Expression::Natural(NaturalExpr::Var(var)),
288            Type::Integer => Expression::Integer(IntegerExpr::Var(var)),
289            Type::Float => Expression::Float(FloatExpr::Var(var)),
290        }
291    }
292
293    /// Creates an [`Expression`] that predicates the equality of `self` and `rhs`,
294    /// and returns error if comparison is not possible.
295    ///
296    /// Equality of Boolean is represented as "if and only if".
297    ///
298    /// Equality of numerical types automatically casts the one of most-restrictive type to the less restrictive type of the other one:
299    /// for example, [`NaturalExpr`] can be cast to [`IntegerExpr`] or [`FloatExpr`];
300    /// and `[IntegerExpr]` can be cast to `[FloatExpr]`.
301    pub fn equal_to(self, rhs: Self) -> Result<BooleanExpr<V>, TypeError> {
302        match self {
303            Expression::Boolean(boolean_expr) => match rhs {
304                Expression::Boolean(boolean_expr_rhs) => {
305                    Ok(BooleanExpr::Implies(Box::new((
306                        boolean_expr.clone(),
307                        boolean_expr_rhs.clone(),
308                    ))) & BooleanExpr::Implies(Box::new((boolean_expr_rhs, boolean_expr))))
309                }
310                Expression::Natural(_) | Expression::Integer(_) | Expression::Float(_) => {
311                    Err(TypeError::TypeMismatch)
312                }
313            },
314            Expression::Natural(natural_expr) => match rhs {
315                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
316                Expression::Natural(natural_expr_rhs) => {
317                    Ok(BooleanExpr::NatEqual(natural_expr, natural_expr_rhs))
318                }
319                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::IntEqual(
320                    IntegerExpr::from(natural_expr),
321                    integer_expr_rhs,
322                )),
323                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatEqual(
324                    FloatExpr::Nat(natural_expr),
325                    float_expr_rhs,
326                )),
327            },
328            Expression::Integer(integer_expr) => match rhs {
329                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
330                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::IntEqual(
331                    integer_expr,
332                    IntegerExpr::from(natural_expr_rhs),
333                )),
334                Expression::Integer(integer_expr_rhs) => {
335                    Ok(BooleanExpr::IntEqual(integer_expr, integer_expr_rhs))
336                }
337                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatEqual(
338                    FloatExpr::Int(integer_expr),
339                    float_expr_rhs,
340                )),
341            },
342            Expression::Float(float_expr) => match rhs {
343                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
344                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::FloatEqual(
345                    float_expr,
346                    FloatExpr::Nat(natural_expr_rhs),
347                )),
348                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::FloatEqual(
349                    float_expr,
350                    FloatExpr::Int(integer_expr_rhs),
351                )),
352                Expression::Float(float_expr_rhs) => {
353                    Ok(BooleanExpr::FloatEqual(float_expr, float_expr_rhs))
354                }
355            },
356        }
357    }
358
359    /// Creates a [`BooleanExpr`] that compares numerical expressions `self` and `rhs`,
360    /// and returns error if comparison is not possible.
361    ///
362    /// Equality of numerical types automatically casts the one of most-restrictive type to the less restrictive type of the other one;
363    /// see [`Self::equal_to`].
364    pub fn greater_than_or_equal_to(self, rhs: Self) -> Result<BooleanExpr<V>, TypeError> {
365        match self {
366            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
367            Expression::Natural(natural_expr) => match rhs {
368                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
369                Expression::Natural(natural_expr_rhs) => {
370                    Ok(BooleanExpr::NatGreaterEq(natural_expr, natural_expr_rhs))
371                }
372                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::IntGreaterEq(
373                    IntegerExpr::from(natural_expr),
374                    integer_expr_rhs,
375                )),
376                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatGreaterEq(
377                    FloatExpr::Nat(natural_expr),
378                    float_expr_rhs,
379                )),
380            },
381            Expression::Integer(integer_expr) => match rhs {
382                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
383                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::IntGreaterEq(
384                    integer_expr,
385                    IntegerExpr::from(natural_expr_rhs),
386                )),
387                Expression::Integer(integer_expr_rhs) => {
388                    Ok(BooleanExpr::IntGreaterEq(integer_expr, integer_expr_rhs))
389                }
390                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatGreaterEq(
391                    FloatExpr::Int(integer_expr),
392                    float_expr_rhs,
393                )),
394            },
395            Expression::Float(float_expr) => match rhs {
396                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
397                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::FloatGreaterEq(
398                    float_expr,
399                    FloatExpr::Nat(natural_expr_rhs),
400                )),
401                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::FloatGreaterEq(
402                    float_expr,
403                    FloatExpr::Int(integer_expr_rhs),
404                )),
405                Expression::Float(float_expr_rhs) => {
406                    Ok(BooleanExpr::FloatGreaterEq(float_expr, float_expr_rhs))
407                }
408            },
409        }
410    }
411
412    /// Creates a [`BooleanExpr`] that compares numerical expressions `self` and `rhs`,
413    /// and returns error if comparison is not possible.
414    ///
415    /// Equality of numerical types automatically casts the one of most-restrictive type to the less restrictive type of the other one;
416    /// see [`Self::equal_to`].
417    pub fn greater_than(self, rhs: Self) -> Result<BooleanExpr<V>, TypeError> {
418        match self {
419            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
420            Expression::Natural(natural_expr) => match rhs {
421                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
422                Expression::Natural(natural_expr_rhs) => {
423                    Ok(BooleanExpr::NatGreater(natural_expr, natural_expr_rhs))
424                }
425                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::IntGreater(
426                    IntegerExpr::from(natural_expr),
427                    integer_expr_rhs,
428                )),
429                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatGreater(
430                    FloatExpr::from(natural_expr),
431                    float_expr_rhs,
432                )),
433            },
434            Expression::Integer(integer_expr) => match rhs {
435                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
436                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::IntGreater(
437                    integer_expr,
438                    IntegerExpr::from(natural_expr_rhs),
439                )),
440                Expression::Integer(integer_expr_rhs) => {
441                    Ok(BooleanExpr::IntGreater(integer_expr, integer_expr_rhs))
442                }
443                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatGreater(
444                    FloatExpr::from(integer_expr),
445                    float_expr_rhs,
446                )),
447            },
448            Expression::Float(float_expr) => match rhs {
449                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
450                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::FloatGreater(
451                    float_expr,
452                    FloatExpr::from(natural_expr_rhs),
453                )),
454                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::FloatGreater(
455                    float_expr,
456                    FloatExpr::from(integer_expr_rhs),
457                )),
458                Expression::Float(float_expr_rhs) => {
459                    Ok(BooleanExpr::FloatGreater(float_expr, float_expr_rhs))
460                }
461            },
462        }
463    }
464
465    /// Creates a [`BooleanExpr`] that compares numerical expressions `self` and `rhs`,
466    /// and returns error if comparison is not possible.
467    ///
468    /// Equality of numerical types automatically casts the one of most-restrictive type to the less restrictive type of the other one;
469    /// see [`Self::equal_to`].
470    pub fn less_than(self, rhs: Self) -> Result<BooleanExpr<V>, TypeError> {
471        match self {
472            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
473            Expression::Natural(natural_expr) => match rhs {
474                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
475                Expression::Natural(natural_expr_rhs) => {
476                    Ok(BooleanExpr::NatLess(natural_expr, natural_expr_rhs))
477                }
478                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::IntLess(
479                    IntegerExpr::from(natural_expr),
480                    integer_expr_rhs,
481                )),
482                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatLess(
483                    FloatExpr::from(natural_expr),
484                    float_expr_rhs,
485                )),
486            },
487            Expression::Integer(integer_expr) => match rhs {
488                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
489                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::IntLess(
490                    integer_expr,
491                    IntegerExpr::from(natural_expr_rhs),
492                )),
493                Expression::Integer(integer_expr_rhs) => {
494                    Ok(BooleanExpr::IntLess(integer_expr, integer_expr_rhs))
495                }
496                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatLess(
497                    FloatExpr::from(integer_expr),
498                    float_expr_rhs,
499                )),
500            },
501            Expression::Float(float_expr) => match rhs {
502                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
503                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::FloatLess(
504                    float_expr,
505                    FloatExpr::from(natural_expr_rhs),
506                )),
507                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::FloatLess(
508                    float_expr,
509                    FloatExpr::from(integer_expr_rhs),
510                )),
511                Expression::Float(float_expr_rhs) => {
512                    Ok(BooleanExpr::FloatLess(float_expr, float_expr_rhs))
513                }
514            },
515        }
516    }
517
518    /// Creates a [`BooleanExpr`] that compares numerical expressions `self` and `rhs`,
519    /// and returns error if comparison is not possible.
520    ///
521    /// Equality of numerical types automatically casts the one of most-restrictive type to the less restrictive type of the other one;
522    /// see [`Self::equal_to`].
523    pub fn less_than_or_equal_to(self, rhs: Self) -> Result<BooleanExpr<V>, TypeError> {
524        match self {
525            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
526            Expression::Natural(natural_expr) => match rhs {
527                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
528                Expression::Natural(natural_expr_rhs) => {
529                    Ok(BooleanExpr::NatLessEq(natural_expr, natural_expr_rhs))
530                }
531                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::IntLessEq(
532                    IntegerExpr::from(natural_expr),
533                    integer_expr_rhs,
534                )),
535                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatLessEq(
536                    FloatExpr::Nat(natural_expr),
537                    float_expr_rhs,
538                )),
539            },
540            Expression::Integer(integer_expr) => match rhs {
541                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
542                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::IntLessEq(
543                    integer_expr,
544                    IntegerExpr::from(natural_expr_rhs),
545                )),
546                Expression::Integer(integer_expr_rhs) => {
547                    Ok(BooleanExpr::IntLessEq(integer_expr, integer_expr_rhs))
548                }
549                Expression::Float(float_expr_rhs) => Ok(BooleanExpr::FloatLessEq(
550                    FloatExpr::Int(integer_expr),
551                    float_expr_rhs,
552                )),
553            },
554            Expression::Float(float_expr) => match rhs {
555                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
556                Expression::Natural(natural_expr_rhs) => Ok(BooleanExpr::FloatLessEq(
557                    float_expr,
558                    FloatExpr::Nat(natural_expr_rhs),
559                )),
560                Expression::Integer(integer_expr_rhs) => Ok(BooleanExpr::FloatLessEq(
561                    float_expr,
562                    FloatExpr::Int(integer_expr_rhs),
563                )),
564                Expression::Float(float_expr_rhs) => {
565                    Ok(BooleanExpr::FloatLessEq(float_expr, float_expr_rhs))
566                }
567            },
568        }
569    }
570
571    /// Creates a [`BooleanExpr`] that takes the minimum of two numerical expressions `self` and `rhs`,
572    /// and returns error if comparison is not possible.
573    pub fn min(self, rhs: Self) -> Result<Self, TypeError> {
574        match self {
575            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
576            Expression::Natural(natural_expr) => match rhs {
577                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
578                Expression::Natural(natural_expr_rhs) => Ok(Expression::Natural(NaturalExpr::Min(
579                    Box::new((natural_expr, natural_expr_rhs)),
580                ))),
581                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Min(
582                    Box::new((IntegerExpr::Nat(natural_expr), integer_expr_rhs)),
583                ))),
584                Expression::Float(float_expr_rhs) => Ok(Expression::Float(FloatExpr::Min(
585                    Box::new((FloatExpr::Nat(natural_expr), float_expr_rhs)),
586                ))),
587            },
588            Expression::Integer(integer_expr) => match rhs {
589                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
590                Expression::Natural(natural_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Min(
591                    Box::new((integer_expr, IntegerExpr::Nat(natural_expr_rhs))),
592                ))),
593                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Min(
594                    Box::new((integer_expr, integer_expr_rhs)),
595                ))),
596                Expression::Float(float_expr_rhs) => Ok(Expression::Float(FloatExpr::Min(
597                    Box::new((FloatExpr::Int(integer_expr), float_expr_rhs)),
598                ))),
599            },
600            Expression::Float(float_expr) => match rhs {
601                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
602                Expression::Natural(natural_expr_rhs) => Ok(Expression::Float(FloatExpr::Min(
603                    Box::new((float_expr, FloatExpr::Nat(natural_expr_rhs))),
604                ))),
605                Expression::Integer(integer_expr_rhs) => Ok(Expression::Float(FloatExpr::Min(
606                    Box::new((float_expr, FloatExpr::Int(integer_expr_rhs))),
607                ))),
608                Expression::Float(float_expr_rhs) => Ok(Expression::Float(FloatExpr::Min(
609                    Box::new((float_expr, float_expr_rhs)),
610                ))),
611            },
612        }
613    }
614
615    /// Creates a [`BooleanExpr`] that takes the maximum of two numerical expressions `self` and `rhs`,
616    /// and returns error if comparison is not possible.
617    pub fn max(self, rhs: Self) -> Result<Self, TypeError> {
618        match self {
619            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
620            Expression::Natural(natural_expr) => match rhs {
621                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
622                Expression::Natural(natural_expr_rhs) => Ok(Expression::Natural(NaturalExpr::Max(
623                    Box::new((natural_expr, natural_expr_rhs)),
624                ))),
625                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Max(
626                    Box::new((IntegerExpr::Nat(natural_expr), integer_expr_rhs)),
627                ))),
628                Expression::Float(float_expr_rhs) => Ok(Expression::Float(FloatExpr::Max(
629                    Box::new((FloatExpr::Nat(natural_expr), float_expr_rhs)),
630                ))),
631            },
632            Expression::Integer(integer_expr) => match rhs {
633                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
634                Expression::Natural(natural_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Max(
635                    Box::new((integer_expr, IntegerExpr::Nat(natural_expr_rhs))),
636                ))),
637                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Max(
638                    Box::new((integer_expr, integer_expr_rhs)),
639                ))),
640                Expression::Float(float_expr_rhs) => Ok(Expression::Float(FloatExpr::Max(
641                    Box::new((FloatExpr::Int(integer_expr), float_expr_rhs)),
642                ))),
643            },
644            Expression::Float(float_expr) => match rhs {
645                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
646                Expression::Natural(natural_expr_rhs) => Ok(Expression::Float(FloatExpr::Max(
647                    Box::new((float_expr, FloatExpr::Nat(natural_expr_rhs))),
648                ))),
649                Expression::Integer(integer_expr_rhs) => Ok(Expression::Float(FloatExpr::Max(
650                    Box::new((float_expr, FloatExpr::Int(integer_expr_rhs))),
651                ))),
652                Expression::Float(float_expr_rhs) => Ok(Expression::Float(FloatExpr::Max(
653                    Box::new((float_expr, float_expr_rhs)),
654                ))),
655            },
656        }
657    }
658
659    /// Creates an if-then-else expression
660    pub fn ite(self, then: Self, r#else: Self) -> Result<Self, TypeError> {
661        if let Expression::Boolean(r#if) = self {
662            r#if.ite(then, r#else)
663        } else {
664            Err(TypeError::TypeMismatch)
665        }
666    }
667}
668
669impl<V: Clone> Neg for Expression<V> {
670    type Output = Result<Expression<V>, TypeError>;
671
672    fn neg(self) -> Self::Output {
673        match self {
674            Expression::Boolean(_) | Expression::Natural(_) => Err(TypeError::TypeMismatch),
675            Expression::Integer(integer_expr) => Ok(Expression::Integer(-integer_expr)),
676            Expression::Float(float_expr) => Ok(Expression::Float(-float_expr)),
677        }
678    }
679}
680
681impl<V: Clone> Not for Expression<V> {
682    type Output = Result<Expression<V>, TypeError>;
683
684    fn not(self) -> Self::Output {
685        match self {
686            Expression::Boolean(boolean_expr) => Ok(Expression::Boolean(!boolean_expr)),
687            Expression::Natural(_) | Expression::Integer(_) | Expression::Float(_) => {
688                Err(TypeError::TypeMismatch)
689            }
690        }
691    }
692}
693
694impl<V: Clone> Add for Expression<V> {
695    type Output = Result<Self, TypeError>;
696
697    fn add(self, rhs: Self) -> Self::Output {
698        match self {
699            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
700            Expression::Natural(natural_expr) => match rhs {
701                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
702                Expression::Natural(natural_expr_rhs) => {
703                    Ok(Expression::Natural(natural_expr + natural_expr_rhs))
704                }
705                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(
706                    IntegerExpr::from(natural_expr) + integer_expr_rhs,
707                )),
708                Expression::Float(float_expr_rhs) => Ok(Expression::Float(
709                    FloatExpr::from(natural_expr) + float_expr_rhs,
710                )),
711            },
712            Expression::Integer(integer_expr) => match rhs {
713                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
714                Expression::Natural(natural_expr_rhs) => Ok(Expression::Integer(
715                    integer_expr + IntegerExpr::from(natural_expr_rhs),
716                )),
717                Expression::Integer(integer_expr_rhs) => {
718                    Ok(Expression::Integer(integer_expr + integer_expr_rhs))
719                }
720                Expression::Float(float_expr_rhs) => Ok(Expression::Float(
721                    FloatExpr::from(integer_expr) + float_expr_rhs,
722                )),
723            },
724            Expression::Float(float_expr) => match rhs {
725                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
726                Expression::Natural(natural_expr_rhs) => Ok(Expression::Float(
727                    float_expr + FloatExpr::from(natural_expr_rhs),
728                )),
729                Expression::Integer(integer_expr_rhs) => Ok(Expression::Float(
730                    float_expr + FloatExpr::from(integer_expr_rhs),
731                )),
732                Expression::Float(float_expr_rhs) => {
733                    Ok(Expression::Float(float_expr + float_expr_rhs))
734                }
735            },
736        }
737    }
738}
739
740impl<V: Clone> Mul for Expression<V> {
741    type Output = Result<Self, TypeError>;
742
743    fn mul(self, rhs: Self) -> Self::Output {
744        match self {
745            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
746            Expression::Natural(natural_expr) => match rhs {
747                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
748                Expression::Natural(natural_expr_rhs) => {
749                    Ok(Expression::Natural(natural_expr * natural_expr_rhs))
750                }
751                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(
752                    IntegerExpr::from(natural_expr) * integer_expr_rhs,
753                )),
754                Expression::Float(float_expr_rhs) => Ok(Expression::Float(
755                    FloatExpr::from(natural_expr) * float_expr_rhs,
756                )),
757            },
758            Expression::Integer(integer_expr) => match rhs {
759                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
760                Expression::Natural(natural_expr_rhs) => Ok(Expression::Integer(
761                    integer_expr * IntegerExpr::from(natural_expr_rhs),
762                )),
763                Expression::Integer(integer_expr_rhs) => {
764                    Ok(Expression::Integer(integer_expr * integer_expr_rhs))
765                }
766                Expression::Float(float_expr_rhs) => Ok(Expression::Float(
767                    FloatExpr::from(integer_expr) * float_expr_rhs,
768                )),
769            },
770            Expression::Float(float_expr) => match rhs {
771                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
772                Expression::Natural(natural_expr_rhs) => Ok(Expression::Float(
773                    float_expr * FloatExpr::from(natural_expr_rhs),
774                )),
775                Expression::Integer(integer_expr_rhs) => Ok(Expression::Float(
776                    float_expr * FloatExpr::from(integer_expr_rhs),
777                )),
778                Expression::Float(float_expr_rhs) => {
779                    Ok(Expression::Float(float_expr * float_expr_rhs))
780                }
781            },
782        }
783    }
784}
785
786impl<V: Clone> Div for Expression<V> {
787    type Output = Result<Self, TypeError>;
788
789    fn div(self, rhs: Self) -> Self::Output {
790        match self {
791            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
792            Expression::Natural(natural_expr) => match rhs {
793                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
794                Expression::Natural(natural_expr_rhs) => {
795                    Ok(Expression::Natural(natural_expr / natural_expr_rhs))
796                }
797                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(
798                    IntegerExpr::from(natural_expr) / integer_expr_rhs,
799                )),
800                Expression::Float(float_expr_rhs) => Ok(Expression::Float(
801                    FloatExpr::from(natural_expr) / float_expr_rhs,
802                )),
803            },
804            Expression::Integer(integer_expr) => match rhs {
805                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
806                Expression::Natural(natural_expr_rhs) => Ok(Expression::Integer(
807                    integer_expr / IntegerExpr::from(natural_expr_rhs),
808                )),
809                Expression::Integer(integer_expr_rhs) => {
810                    Ok(Expression::Integer(integer_expr / integer_expr_rhs))
811                }
812                Expression::Float(float_expr_rhs) => Ok(Expression::Float(
813                    FloatExpr::from(integer_expr) / float_expr_rhs,
814                )),
815            },
816            Expression::Float(float_expr) => match rhs {
817                Expression::Boolean(_) => Err(TypeError::TypeMismatch),
818                Expression::Natural(natural_expr_rhs) => Ok(Expression::Float(
819                    float_expr / FloatExpr::from(natural_expr_rhs),
820                )),
821                Expression::Integer(integer_expr_rhs) => Ok(Expression::Float(
822                    float_expr / FloatExpr::from(integer_expr_rhs),
823                )),
824                Expression::Float(float_expr_rhs) => {
825                    Ok(Expression::Float(float_expr / float_expr_rhs))
826                }
827            },
828        }
829    }
830}
831
832impl<V: Clone> Rem for Expression<V> {
833    type Output = Result<Self, TypeError>;
834
835    fn rem(self, rhs: Self) -> Self::Output {
836        match self {
837            Expression::Natural(natural_expr) => match rhs {
838                Expression::Natural(natural_expr_rhs) => Ok(Expression::Natural(NaturalExpr::Rem(
839                    Box::new((natural_expr, natural_expr_rhs)),
840                ))),
841                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Rem(
842                    Box::new((IntegerExpr::from(natural_expr), integer_expr_rhs)),
843                ))),
844                Expression::Boolean(_) | Expression::Float(_) => Err(TypeError::TypeMismatch),
845            },
846            Expression::Integer(integer_expr) => match rhs {
847                Expression::Natural(natural_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Rem(
848                    Box::new((integer_expr, IntegerExpr::from(natural_expr_rhs))),
849                ))),
850                Expression::Integer(integer_expr_rhs) => Ok(Expression::Integer(IntegerExpr::Rem(
851                    Box::new((integer_expr, integer_expr_rhs)),
852                ))),
853                Expression::Boolean(_) | Expression::Float(_) => Err(TypeError::TypeMismatch),
854            },
855            Expression::Boolean(_) | Expression::Float(_) => Err(TypeError::TypeMismatch),
856        }
857    }
858}
859
860impl<V: Clone> BitAnd for Expression<V> {
861    type Output = Result<Self, TypeError>;
862
863    fn bitand(self, rhs: Self) -> Self::Output {
864        if let Expression::Boolean(lhs) = self {
865            if let Expression::Boolean(rhs) = rhs {
866                Ok(Expression::Boolean(lhs & rhs))
867            } else {
868                Err(TypeError::TypeMismatch)
869            }
870        } else {
871            Err(TypeError::TypeMismatch)
872        }
873    }
874}
875
876impl<V: Clone> BitOr for Expression<V> {
877    type Output = Result<Self, TypeError>;
878
879    fn bitor(self, rhs: Self) -> Self::Output {
880        if let Expression::Boolean(lhs) = self {
881            if let Expression::Boolean(rhs) = rhs {
882                Ok(Expression::Boolean(lhs | rhs))
883            } else {
884                Err(TypeError::TypeMismatch)
885            }
886        } else {
887            Err(TypeError::TypeMismatch)
888        }
889    }
890}