espresso_logic/expression/
mod.rs1use std::collections::BTreeSet;
8use std::fmt;
9use std::ops::{Add, Mul, Not};
10use std::sync::Arc;
11
12mod cover;
13pub use cover::ExprCover;
14
15#[allow(clippy::all)]
17mod parser {
18 #![allow(clippy::all)]
19 #![allow(dead_code)]
20 #![allow(unused_variables)]
21 #![allow(unused_imports)]
22 #![allow(non_snake_case)]
23 #![allow(non_camel_case_types)]
24 #![allow(non_upper_case_globals)]
25 include!(concat!(env!("OUT_DIR"), "/expression/bool_expr.rs"));
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub(crate) enum BoolExprInner {
31 Variable(Arc<str>),
33 And(BoolExpr, BoolExpr),
35 Or(BoolExpr, BoolExpr),
37 Not(BoolExpr),
39 Constant(bool),
41}
42
43#[derive(Clone, PartialEq, Eq)]
70pub struct BoolExpr {
71 inner: Arc<BoolExprInner>,
72}
73
74impl BoolExpr {
75 pub fn variable(name: &str) -> Self {
77 BoolExpr {
78 inner: Arc::new(BoolExprInner::Variable(Arc::from(name))),
79 }
80 }
81
82 pub fn constant(value: bool) -> Self {
84 BoolExpr {
85 inner: Arc::new(BoolExprInner::Constant(value)),
86 }
87 }
88
89 pub fn parse(input: &str) -> Result<Self, String> {
98 parser::ExprParser::new()
99 .parse(input)
100 .map_err(|e| format!("Parse error: {}", e))
101 }
102
103 pub fn collect_variables(&self) -> BTreeSet<Arc<str>> {
108 let mut vars = BTreeSet::new();
109 self.collect_variables_impl(&mut vars);
110 vars
111 }
112
113 fn collect_variables_impl(&self, vars: &mut BTreeSet<Arc<str>>) {
114 match self.inner.as_ref() {
115 BoolExprInner::Variable(name) => {
116 vars.insert(Arc::clone(name));
117 }
118 BoolExprInner::And(left, right) | BoolExprInner::Or(left, right) => {
119 left.collect_variables_impl(vars);
120 right.collect_variables_impl(vars);
121 }
122 BoolExprInner::Not(expr) => {
123 expr.collect_variables_impl(vars);
124 }
125 BoolExprInner::Constant(_) => {}
126 }
127 }
128
129 pub fn and(&self, other: &BoolExpr) -> BoolExpr {
131 BoolExpr {
132 inner: Arc::new(BoolExprInner::And(self.clone(), other.clone())),
133 }
134 }
135
136 pub fn or(&self, other: &BoolExpr) -> BoolExpr {
138 BoolExpr {
139 inner: Arc::new(BoolExprInner::Or(self.clone(), other.clone())),
140 }
141 }
142
143 pub fn not(&self) -> BoolExpr {
145 BoolExpr {
146 inner: Arc::new(BoolExprInner::Not(self.clone())),
147 }
148 }
149
150 pub(crate) fn inner(&self) -> &BoolExprInner {
152 &self.inner
153 }
154
155 pub fn minimize(self) -> std::io::Result<BoolExpr> {
181 use crate::Cover;
182 let mut cover = ExprCover::from_expr(self);
183 cover.minimize()?;
184 Ok(cover.to_expr())
185 }
186}
187
188#[macro_export]
210macro_rules! expr {
211 (( $($inner:tt)* )) => {
213 expr!($($inner)*)
214 };
215
216 (! $e:ident) => {
218 (&$e).not()
219 };
220
221 (! ( $($inner:tt)* )) => {
223 expr!($($inner)*).not()
224 };
225
226 ($a:ident + $b:ident) => {
228 &$a + &$b
229 };
230 ($a:ident * $b:ident) => {
231 &$a * &$b
232 };
233
234 ($a:ident * $b:ident + $c:ident * $d:ident * $e:ident) => {
236 $a.and(&$b).or(&$c.and(&$d).and(&$e))
237 };
238 ($a:ident * $b:ident + $c:ident * $d:ident) => {
239 $a.and(&$b).or(&$c.and(&$d))
240 };
241 ($a:ident * $b:ident + ! $c:ident * $d:ident) => {
242 $a.and(&$b).or(&$c.not().and(&$d))
243 };
244 ($a:ident * $b:ident + $c:ident * ! $d:ident) => {
245 $a.and(&$b).or(&$c.and(&$d.not()))
246 };
247 ($a:ident * $b:ident + ! $c:ident * ! $d:ident) => {
248 $a.and(&$b).or(&$c.not().and(&$d.not()))
249 };
250 ($a:ident * ! $b:ident + ! $c:ident * $d:ident) => {
251 $a.and(&$b.not()).or(&$c.not().and(&$d))
252 };
253 ($a:ident * ! $b:ident + $c:ident * ! $d:ident) => {
254 $a.and(&$b.not()).or(&$c.and(&$d.not()))
255 };
256 ($a:ident * ! $b:ident + ! $c:ident * ! $d:ident) => {
257 $a.and(&$b.not()).or(&$c.not().and(&$d.not()))
258 };
259 (! $a:ident * $b:ident + $c:ident * ! $d:ident) => {
260 $a.not().and(&$b).or(&$c.and(&$d.not()))
261 };
262 (! $a:ident * $b:ident + ! $c:ident * $d:ident) => {
263 $a.not().and(&$b).or(&$c.not().and(&$d))
264 };
265 (! $a:ident * $b:ident + ! $c:ident * ! $d:ident) => {
266 $a.not().and(&$b).or(&$c.not().and(&$d.not()))
267 };
268 (! $a:ident * ! $b:ident + $c:ident * $d:ident) => {
269 $a.not().and(&$b.not()).or(&$c.and(&$d))
270 };
271 (! $a:ident * ! $b:ident + $c:ident * ! $d:ident) => {
272 $a.not().and(&$b.not()).or(&$c.and(&$d.not()))
273 };
274 (! $a:ident * ! $b:ident + ! $c:ident * $d:ident) => {
275 $a.not().and(&$b.not()).or(&$c.not().and(&$d))
276 };
277 (! $a:ident * ! $b:ident + ! $c:ident * ! $d:ident) => {
278 $a.not().and(&$b.not()).or(&$c.not().and(&$d.not()))
279 };
280
281 ($a:ident * $b:ident * $c:ident) => {
283 &$a * &$b * &$c
284 };
285
286 (( $($a:tt)* ) * $b:ident) => {
288 expr!(( $($a)* )).and(&$b)
289 };
290 ($a:ident * ( $($b:tt)* )) => {
291 $a.and(&expr!(( $($b)* )))
292 };
293 (( $($a:tt)* ) * ( $($b:tt)* )) => {
294 expr!(( $($a)* )).and(&expr!(( $($b)* )))
295 };
296 (! ( $($a:tt)* ) * $b:ident) => {
297 expr!(! ( $($a)* )).and(&$b)
298 };
299 ($a:ident * ! ( $($b:tt)* )) => {
300 $a.and(&expr!(! ( $($b)* )))
301 };
302 (( $($a:tt)* ) * ! $b:ident) => {
303 expr!(( $($a)* )).and(&$b.not())
304 };
305 (! $a:ident * ( $($b:tt)* )) => {
306 $a.not().and(&expr!(( $($b)* )))
307 };
308
309 (( $($a:tt)* ) + $b:ident) => {
311 expr!(( $($a)* )).or(&$b)
312 };
313 ($a:ident + ( $($b:tt)* )) => {
314 $a.or(&expr!(( $($b)* )))
315 };
316 (( $($a:tt)* ) + ( $($b:tt)* )) => {
317 expr!(( $($a)* )).or(&expr!(( $($b)* )))
318 };
319 (! ( $($a:tt)* ) + $b:ident) => {
320 expr!(! ( $($a)* )).or(&$b)
321 };
322 ($a:ident + ! ( $($b:tt)* )) => {
323 $a.or(&expr!(! ( $($b)* )))
324 };
325 (( $($a:tt)* ) + ! $b:ident) => {
326 expr!(( $($a)* )).or(&$b.not())
327 };
328 (! $a:ident + ( $($b:tt)* )) => {
329 $a.not().or(&expr!(( $($b)* )))
330 };
331
332 ($e:ident) => {
334 $e
335 };
336}
337
338impl fmt::Debug for BoolExpr {
339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340 match self.inner.as_ref() {
341 BoolExprInner::Variable(name) => write!(f, "{}", name),
342 BoolExprInner::And(left, right) => write!(f, "({:?} * {:?})", left, right),
343 BoolExprInner::Or(left, right) => write!(f, "({:?} + {:?})", left, right),
344 BoolExprInner::Not(expr) => write!(f, "~{:?}", expr),
345 BoolExprInner::Constant(val) => write!(f, "{}", if *val { "1" } else { "0" }),
346 }
347 }
348}
349
350impl fmt::Display for BoolExpr {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 write!(f, "{:?}", self)
353 }
354}
355
356impl Mul for &BoolExpr {
362 type Output = BoolExpr;
363
364 fn mul(self, rhs: &BoolExpr) -> BoolExpr {
365 self.and(rhs)
366 }
367}
368
369impl Mul for BoolExpr {
371 type Output = BoolExpr;
372
373 fn mul(self, rhs: BoolExpr) -> BoolExpr {
374 self.and(&rhs)
375 }
376}
377
378impl Add for &BoolExpr {
380 type Output = BoolExpr;
381
382 fn add(self, rhs: &BoolExpr) -> BoolExpr {
383 self.or(rhs)
384 }
385}
386
387impl Add for BoolExpr {
389 type Output = BoolExpr;
390
391 fn add(self, rhs: BoolExpr) -> BoolExpr {
392 self.or(&rhs)
393 }
394}
395
396impl Not for &BoolExpr {
398 type Output = BoolExpr;
399
400 fn not(self) -> BoolExpr {
401 BoolExpr::not(self)
402 }
403}
404
405impl Not for BoolExpr {
407 type Output = BoolExpr;
408
409 fn not(self) -> BoolExpr {
410 BoolExpr::not(&self)
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417
418 #[test]
419 fn test_variable_creation() {
420 let a = BoolExpr::variable("a");
421 let b = BoolExpr::variable("b");
422 let a2 = BoolExpr::variable("a");
423
424 assert_eq!(a, a2);
426 assert_ne!(a, b);
427 }
428
429 #[test]
430 fn test_constant_creation() {
431 let t = BoolExpr::constant(true);
432 let f = BoolExpr::constant(false);
433
434 assert_eq!(t, BoolExpr::constant(true));
435 assert_ne!(t, f);
436 }
437
438 #[test]
439 fn test_method_api() {
440 let a = BoolExpr::variable("a");
441 let b = BoolExpr::variable("b");
442
443 let and_expr = a.and(&b);
445 match and_expr.inner() {
446 BoolExprInner::And(_, _) => {}
447 _ => panic!("Expected And expression"),
448 }
449
450 let or_expr = a.or(&b);
452 match or_expr.inner() {
453 BoolExprInner::Or(_, _) => {}
454 _ => panic!("Expected Or expression"),
455 }
456
457 let not_expr = a.not();
459 match not_expr.inner() {
460 BoolExprInner::Not(_) => {}
461 _ => panic!("Expected Not expression"),
462 }
463 }
464
465 #[test]
466 fn test_complex_expression() {
467 let a = BoolExpr::variable("a");
468 let b = BoolExpr::variable("b");
469 let c = BoolExpr::variable("c");
470
471 let expr = a.and(&b).or(&a.not().and(&c));
473
474 match expr.inner() {
475 BoolExprInner::Or(_, _) => {}
476 _ => panic!("Expected Or at top level"),
477 }
478 }
479
480 #[test]
481 fn test_collect_variables() {
482 let a = BoolExpr::variable("a");
483 let b = BoolExpr::variable("b");
484 let c = BoolExpr::variable("c");
485
486 let expr = a.and(&b).or(&c);
488 let vars = expr.collect_variables();
489
490 assert_eq!(vars.len(), 3);
491 let var_names: Vec<String> = vars.iter().map(|s| s.to_string()).collect();
492 assert_eq!(var_names, vec!["a", "b", "c"]); }
494}