1use super::{
2 BoolFunctionExpr, BoolListExpr, CallArg, CustomExpr, CustomFieldAccess, Expr, FloatExpr,
3 IntExpr, ListExpr, PanicExpr, StringExpr, TupleExpr,
4};
5use crate::plan::{BitArrayExpr, BitArrayPattern, CustomPattern};
6use crate::plan::{BoolLocalId, ConstantBoolReference, FunctionInstantiation, HostCallSite, Step};
7use ecow::EcoString;
8use num_bigint::BigInt;
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct BoolExpr {
12 kind: BoolExprKind,
13}
14
15#[derive(Debug, Clone, PartialEq)]
16pub(crate) enum BoolExprKind {
17 Value(bool),
18 Constant(ConstantBoolReference),
19 LocalGet {
20 local: BoolLocalId,
21 name: EcoString,
22 },
23 Call {
24 function: FunctionInstantiation,
25 args: Vec<CallArg>,
26 site: HostCallSite,
27 },
28 FunctionCall {
29 function: Box<BoolFunctionExpr>,
30 args: Vec<CallArg>,
31 site: HostCallSite,
32 },
33 TupleIndex {
34 tuple: Box<TupleExpr>,
35 index: usize,
36 },
37 CustomField(CustomFieldAccess),
38 ListIndex {
39 list: Box<BoolListExpr>,
40 index: usize,
41 },
42 Panic(PanicExpr),
43 Not(Box<BoolExpr>),
44 LtInt {
45 left: Box<IntExpr>,
46 right: Box<IntExpr>,
47 },
48 LtEqInt {
49 left: Box<IntExpr>,
50 right: Box<IntExpr>,
51 },
52 GtInt {
53 left: Box<IntExpr>,
54 right: Box<IntExpr>,
55 },
56 GtEqInt {
57 left: Box<IntExpr>,
58 right: Box<IntExpr>,
59 },
60 LtFloat {
61 left: Box<FloatExpr>,
62 right: Box<FloatExpr>,
63 },
64 LtEqFloat {
65 left: Box<FloatExpr>,
66 right: Box<FloatExpr>,
67 },
68 GtFloat {
69 left: Box<FloatExpr>,
70 right: Box<FloatExpr>,
71 },
72 GtEqFloat {
73 left: Box<FloatExpr>,
74 right: Box<FloatExpr>,
75 },
76 Equal {
77 left: Box<Expr>,
78 right: Box<Expr>,
79 },
80 NotEqual {
81 left: Box<Expr>,
82 right: Box<Expr>,
83 },
84 StringStartsWith {
85 value: Box<StringExpr>,
86 prefix: EcoString,
87 },
88 ListLengthEquals {
89 value: Box<ListExpr>,
90 length: usize,
91 },
92 ListLengthAtLeast {
93 value: Box<ListExpr>,
94 length: usize,
95 },
96 BitArrayMatches {
97 value: Box<BitArrayExpr>,
98 pattern: BitArrayPattern,
99 },
100 CustomMatches {
101 value: Box<CustomExpr>,
102 pattern: CustomPattern,
103 },
104 And {
105 left: Box<BoolExpr>,
106 right: Box<BoolExpr>,
107 },
108 Or {
109 left: Box<BoolExpr>,
110 right: Box<BoolExpr>,
111 },
112 BoolCase {
113 subject: Box<BoolExpr>,
114 true_: Box<BoolExpr>,
115 false_: Box<BoolExpr>,
116 },
117 IntCase {
118 subject: Box<IntExpr>,
119 clauses: Vec<(BigInt, BoolExpr)>,
120 fallback: Box<BoolExpr>,
121 },
122 StringCase {
123 subject: Box<StringExpr>,
124 clauses: Vec<(EcoString, BoolExpr)>,
125 fallback: Box<BoolExpr>,
126 },
127 FloatCase {
128 subject: Box<FloatExpr>,
129 clauses: Vec<(f64, BoolExpr)>,
130 fallback: Box<BoolExpr>,
131 },
132 Block {
133 steps: Vec<Step>,
134 return_: Box<BoolExpr>,
135 },
136}
137
138impl BoolExpr {
139 pub(crate) fn value(value: bool) -> Self {
140 Self {
141 kind: BoolExprKind::Value(value),
142 }
143 }
144
145 pub(in crate::plan::module) fn constant(reference: ConstantBoolReference) -> Self {
146 Self {
147 kind: BoolExprKind::Constant(reference),
148 }
149 }
150
151 pub(crate) fn local_get(local: BoolLocalId, name: EcoString) -> Self {
152 Self {
153 kind: BoolExprKind::LocalGet { local, name },
154 }
155 }
156
157 #[cfg(test)]
158 pub(crate) fn call(function: FunctionInstantiation, args: Vec<CallArg>) -> Self {
159 Self::call_at(function, args, HostCallSite::unknown())
160 }
161
162 pub(crate) fn call_at(
163 function: FunctionInstantiation,
164 args: Vec<CallArg>,
165 site: HostCallSite,
166 ) -> Self {
167 Self {
168 kind: BoolExprKind::Call {
169 function,
170 args,
171 site,
172 },
173 }
174 }
175
176 #[cfg(test)]
177 pub(crate) fn function_call(function: BoolFunctionExpr, args: Vec<CallArg>) -> Self {
178 Self::function_call_at(function, args, HostCallSite::unknown())
179 }
180
181 pub(crate) fn function_call_at(
182 function: BoolFunctionExpr,
183 args: Vec<CallArg>,
184 site: HostCallSite,
185 ) -> Self {
186 Self {
187 kind: BoolExprKind::FunctionCall {
188 function: Box::new(function),
189 args,
190 site,
191 },
192 }
193 }
194
195 pub(crate) fn tuple_index(tuple: TupleExpr, index: usize) -> Self {
196 Self {
197 kind: BoolExprKind::TupleIndex {
198 tuple: Box::new(tuple),
199 index,
200 },
201 }
202 }
203
204 pub(crate) fn custom_field(access: CustomFieldAccess) -> Self {
205 Self {
206 kind: BoolExprKind::CustomField(access),
207 }
208 }
209
210 pub(crate) fn list_index(list: impl Into<BoolListExpr>, index: usize) -> Self {
211 Self {
212 kind: BoolExprKind::ListIndex {
213 list: Box::new(list.into()),
214 index,
215 },
216 }
217 }
218
219 pub(crate) fn panic(panic: PanicExpr) -> Self {
220 Self {
221 kind: BoolExprKind::Panic(panic),
222 }
223 }
224
225 pub(crate) fn not(value: BoolExpr) -> Self {
226 Self {
227 kind: BoolExprKind::Not(Box::new(value)),
228 }
229 }
230
231 pub(crate) fn lt_int(left: IntExpr, right: IntExpr) -> Self {
232 Self {
233 kind: BoolExprKind::LtInt {
234 left: Box::new(left),
235 right: Box::new(right),
236 },
237 }
238 }
239
240 pub(crate) fn lte_int(left: IntExpr, right: IntExpr) -> Self {
241 Self {
242 kind: BoolExprKind::LtEqInt {
243 left: Box::new(left),
244 right: Box::new(right),
245 },
246 }
247 }
248
249 pub(crate) fn gt_int(left: IntExpr, right: IntExpr) -> Self {
250 Self {
251 kind: BoolExprKind::GtInt {
252 left: Box::new(left),
253 right: Box::new(right),
254 },
255 }
256 }
257
258 pub(crate) fn gte_int(left: IntExpr, right: IntExpr) -> Self {
259 Self {
260 kind: BoolExprKind::GtEqInt {
261 left: Box::new(left),
262 right: Box::new(right),
263 },
264 }
265 }
266
267 pub(crate) fn lt_float(left: FloatExpr, right: FloatExpr) -> Self {
268 Self {
269 kind: BoolExprKind::LtFloat {
270 left: Box::new(left),
271 right: Box::new(right),
272 },
273 }
274 }
275
276 pub(crate) fn lte_float(left: FloatExpr, right: FloatExpr) -> Self {
277 Self {
278 kind: BoolExprKind::LtEqFloat {
279 left: Box::new(left),
280 right: Box::new(right),
281 },
282 }
283 }
284
285 pub(crate) fn gt_float(left: FloatExpr, right: FloatExpr) -> Self {
286 Self {
287 kind: BoolExprKind::GtFloat {
288 left: Box::new(left),
289 right: Box::new(right),
290 },
291 }
292 }
293
294 pub(crate) fn gte_float(left: FloatExpr, right: FloatExpr) -> Self {
295 Self {
296 kind: BoolExprKind::GtEqFloat {
297 left: Box::new(left),
298 right: Box::new(right),
299 },
300 }
301 }
302
303 pub(crate) fn equal(left: Expr, right: Expr) -> Self {
304 Self {
305 kind: BoolExprKind::Equal {
306 left: Box::new(left),
307 right: Box::new(right),
308 },
309 }
310 }
311
312 pub(crate) fn not_equal(left: Expr, right: Expr) -> Self {
313 Self {
314 kind: BoolExprKind::NotEqual {
315 left: Box::new(left),
316 right: Box::new(right),
317 },
318 }
319 }
320
321 pub(crate) fn string_starts_with(value: StringExpr, prefix: EcoString) -> Self {
322 Self {
323 kind: BoolExprKind::StringStartsWith {
324 value: Box::new(value),
325 prefix,
326 },
327 }
328 }
329
330 pub(crate) fn list_length_equals(value: ListExpr, length: usize) -> Self {
331 Self {
332 kind: BoolExprKind::ListLengthEquals {
333 value: Box::new(value),
334 length,
335 },
336 }
337 }
338
339 pub(crate) fn list_length_at_least(value: ListExpr, length: usize) -> Self {
340 Self {
341 kind: BoolExprKind::ListLengthAtLeast {
342 value: Box::new(value),
343 length,
344 },
345 }
346 }
347
348 pub(crate) fn bit_array_matches(value: BitArrayExpr, pattern: BitArrayPattern) -> Self {
349 Self {
350 kind: BoolExprKind::BitArrayMatches {
351 value: Box::new(value),
352 pattern,
353 },
354 }
355 }
356
357 pub(crate) fn custom_matches(value: CustomExpr, pattern: CustomPattern) -> Self {
358 Self {
359 kind: BoolExprKind::CustomMatches {
360 value: Box::new(value),
361 pattern,
362 },
363 }
364 }
365
366 pub(crate) fn and(left: BoolExpr, right: BoolExpr) -> Self {
367 Self {
368 kind: BoolExprKind::And {
369 left: Box::new(left),
370 right: Box::new(right),
371 },
372 }
373 }
374
375 pub(crate) fn or(left: BoolExpr, right: BoolExpr) -> Self {
376 Self {
377 kind: BoolExprKind::Or {
378 left: Box::new(left),
379 right: Box::new(right),
380 },
381 }
382 }
383
384 pub(crate) fn bool_case(subject: BoolExpr, true_: BoolExpr, false_: BoolExpr) -> Self {
385 Self {
386 kind: BoolExprKind::BoolCase {
387 subject: Box::new(subject),
388 true_: Box::new(true_),
389 false_: Box::new(false_),
390 },
391 }
392 }
393
394 pub(crate) fn int_case(
395 subject: IntExpr,
396 clauses: Vec<(BigInt, BoolExpr)>,
397 fallback: BoolExpr,
398 ) -> Self {
399 Self {
400 kind: BoolExprKind::IntCase {
401 subject: Box::new(subject),
402 clauses,
403 fallback: Box::new(fallback),
404 },
405 }
406 }
407
408 pub(crate) fn string_case(
409 subject: StringExpr,
410 clauses: Vec<(EcoString, BoolExpr)>,
411 fallback: BoolExpr,
412 ) -> Self {
413 Self {
414 kind: BoolExprKind::StringCase {
415 subject: Box::new(subject),
416 clauses,
417 fallback: Box::new(fallback),
418 },
419 }
420 }
421
422 pub(crate) fn float_case(
423 subject: FloatExpr,
424 clauses: Vec<(f64, BoolExpr)>,
425 fallback: BoolExpr,
426 ) -> Self {
427 Self {
428 kind: BoolExprKind::FloatCase {
429 subject: Box::new(subject),
430 clauses,
431 fallback: Box::new(fallback),
432 },
433 }
434 }
435
436 pub(crate) fn block(steps: Vec<Step>, return_: BoolExpr) -> Self {
437 Self {
438 kind: BoolExprKind::Block {
439 steps,
440 return_: Box::new(return_),
441 },
442 }
443 }
444
445 pub(crate) fn kind(&self) -> &BoolExprKind {
446 &self.kind
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use super::{BoolExpr, BoolExprKind};
453 use crate::plan::{
454 BoolFunctionReference, BoolLocalId, Expr, FloatExpr, FunctionInstantiation, FunctionShape,
455 IntExpr, Step, StringExpr, TupleExpr, ValueShape, ValueType,
456 monomorphic_function_instantiation,
457 };
458 use num_bigint::BigInt;
459
460 #[test]
461 fn bool_expr_kind_accessors() {
462 assert_eq!(BoolExpr::value(true).kind(), &BoolExprKind::Value(true),);
463 assert_eq!(
464 BoolExpr::local_get(BoolLocalId(0), "flag".into()).kind(),
465 &BoolExprKind::LocalGet {
466 local: BoolLocalId(0),
467 name: "flag".into(),
468 },
469 );
470 assert_eq!(
471 BoolExpr::call(function_instantiation(), Vec::new()).kind(),
472 &BoolExprKind::Call {
473 function: function_instantiation(),
474 args: Vec::new(),
475 site: crate::plan::HostCallSite::unknown(),
476 },
477 );
478 assert_eq!(
479 BoolExpr::function_call(function_expr(), Vec::new()).kind(),
480 &BoolExprKind::FunctionCall {
481 function: Box::new(function_expr()),
482 args: Vec::new(),
483 site: crate::plan::HostCallSite::unknown(),
484 },
485 );
486 assert_eq!(
487 BoolExpr::tuple_index(tuple_expr(), 0).kind(),
488 &BoolExprKind::TupleIndex {
489 tuple: Box::new(tuple_expr()),
490 index: 0,
491 },
492 );
493 assert_eq!(
494 BoolExpr::not(BoolExpr::value(true)).kind(),
495 &BoolExprKind::Not(Box::new(BoolExpr::value(true))),
496 );
497 assert_eq!(
498 BoolExpr::lt_int(IntExpr::value(1.into()), IntExpr::value(2.into())).kind(),
499 &BoolExprKind::LtInt {
500 left: Box::new(IntExpr::value(1.into())),
501 right: Box::new(IntExpr::value(2.into())),
502 },
503 );
504 assert_eq!(
505 BoolExpr::lte_int(IntExpr::value(1.into()), IntExpr::value(2.into())).kind(),
506 &BoolExprKind::LtEqInt {
507 left: Box::new(IntExpr::value(1.into())),
508 right: Box::new(IntExpr::value(2.into())),
509 },
510 );
511 assert_eq!(
512 BoolExpr::gt_int(IntExpr::value(2.into()), IntExpr::value(1.into())).kind(),
513 &BoolExprKind::GtInt {
514 left: Box::new(IntExpr::value(2.into())),
515 right: Box::new(IntExpr::value(1.into())),
516 },
517 );
518 assert_eq!(
519 BoolExpr::gte_int(IntExpr::value(2.into()), IntExpr::value(1.into())).kind(),
520 &BoolExprKind::GtEqInt {
521 left: Box::new(IntExpr::value(2.into())),
522 right: Box::new(IntExpr::value(1.into())),
523 },
524 );
525 assert_eq!(
526 BoolExpr::lt_float(FloatExpr::value(1.0), FloatExpr::value(2.0)).kind(),
527 &BoolExprKind::LtFloat {
528 left: Box::new(FloatExpr::value(1.0)),
529 right: Box::new(FloatExpr::value(2.0)),
530 },
531 );
532 assert_eq!(
533 BoolExpr::lte_float(FloatExpr::value(1.0), FloatExpr::value(2.0)).kind(),
534 &BoolExprKind::LtEqFloat {
535 left: Box::new(FloatExpr::value(1.0)),
536 right: Box::new(FloatExpr::value(2.0)),
537 },
538 );
539 assert_eq!(
540 BoolExpr::gt_float(FloatExpr::value(2.0), FloatExpr::value(1.0)).kind(),
541 &BoolExprKind::GtFloat {
542 left: Box::new(FloatExpr::value(2.0)),
543 right: Box::new(FloatExpr::value(1.0)),
544 },
545 );
546 assert_eq!(
547 BoolExpr::gte_float(FloatExpr::value(2.0), FloatExpr::value(1.0)).kind(),
548 &BoolExprKind::GtEqFloat {
549 left: Box::new(FloatExpr::value(2.0)),
550 right: Box::new(FloatExpr::value(1.0)),
551 },
552 );
553 assert_eq!(
554 BoolExpr::equal(
555 Expr::int(IntExpr::value(1.into())),
556 Expr::int(IntExpr::value(1.into()))
557 )
558 .kind(),
559 &BoolExprKind::Equal {
560 left: Box::new(Expr::int(IntExpr::value(1.into()))),
561 right: Box::new(Expr::int(IntExpr::value(1.into()))),
562 },
563 );
564 assert_eq!(
565 BoolExpr::not_equal(
566 Expr::bool(BoolExpr::value(true)),
567 Expr::bool(BoolExpr::value(false))
568 )
569 .kind(),
570 &BoolExprKind::NotEqual {
571 left: Box::new(Expr::bool(BoolExpr::value(true))),
572 right: Box::new(Expr::bool(BoolExpr::value(false))),
573 },
574 );
575 assert_eq!(
576 BoolExpr::string_starts_with(StringExpr::value("geam".into()), "ge".into()).kind(),
577 &BoolExprKind::StringStartsWith {
578 value: Box::new(StringExpr::value("geam".into())),
579 prefix: "ge".into(),
580 },
581 );
582 assert_eq!(
583 BoolExpr::and(BoolExpr::value(true), BoolExpr::value(false)).kind(),
584 &BoolExprKind::And {
585 left: Box::new(BoolExpr::value(true)),
586 right: Box::new(BoolExpr::value(false)),
587 },
588 );
589 assert_eq!(
590 BoolExpr::or(BoolExpr::value(true), BoolExpr::value(false)).kind(),
591 &BoolExprKind::Or {
592 left: Box::new(BoolExpr::value(true)),
593 right: Box::new(BoolExpr::value(false)),
594 },
595 );
596 assert_eq!(
597 BoolExpr::bool_case(
598 BoolExpr::value(true),
599 BoolExpr::value(true),
600 BoolExpr::value(false)
601 )
602 .kind(),
603 &BoolExprKind::BoolCase {
604 subject: Box::new(BoolExpr::value(true)),
605 true_: Box::new(BoolExpr::value(true)),
606 false_: Box::new(BoolExpr::value(false)),
607 },
608 );
609 assert_eq!(
610 BoolExpr::int_case(
611 IntExpr::value(1.into()),
612 vec![(1.into(), BoolExpr::value(true))],
613 BoolExpr::value(false)
614 )
615 .kind(),
616 &BoolExprKind::IntCase {
617 subject: Box::new(IntExpr::value(1.into())),
618 clauses: vec![(BigInt::from(1), BoolExpr::value(true))],
619 fallback: Box::new(BoolExpr::value(false)),
620 },
621 );
622 assert_eq!(
623 BoolExpr::string_case(
624 crate::plan::StringExpr::value("a".into()),
625 vec![("a".into(), BoolExpr::value(true))],
626 BoolExpr::value(false)
627 )
628 .kind(),
629 &BoolExprKind::StringCase {
630 subject: Box::new(crate::plan::StringExpr::value("a".into())),
631 clauses: vec![("a".into(), BoolExpr::value(true))],
632 fallback: Box::new(BoolExpr::value(false)),
633 },
634 );
635 assert_eq!(
636 BoolExpr::float_case(
637 FloatExpr::value(1.0),
638 vec![(1.0, BoolExpr::value(true))],
639 BoolExpr::value(false)
640 )
641 .kind(),
642 &BoolExprKind::FloatCase {
643 subject: Box::new(FloatExpr::value(1.0)),
644 clauses: vec![(1.0, BoolExpr::value(true))],
645 fallback: Box::new(BoolExpr::value(false)),
646 },
647 );
648 assert_eq!(
649 BoolExpr::block(
650 vec![Step::evaluate(Expr::bool(BoolExpr::value(false)))],
651 BoolExpr::value(true),
652 )
653 .kind(),
654 &BoolExprKind::Block {
655 steps: vec![Step::evaluate(Expr::bool(BoolExpr::value(false)))],
656 return_: Box::new(BoolExpr::value(true)),
657 },
658 );
659 }
660
661 fn function_expr() -> crate::plan::BoolFunctionExpr {
662 crate::plan::BoolFunctionExpr::reference(BoolFunctionReference::new(
663 function_instantiation(),
664 ))
665 }
666
667 fn function_instantiation() -> FunctionInstantiation {
668 monomorphic_function_instantiation(0, FunctionShape::new(Vec::new(), ValueShape::Bool))
669 }
670
671 fn tuple_expr() -> TupleExpr {
672 TupleExpr::value(
673 vec![Expr::bool(BoolExpr::value(true))],
674 vec![ValueType::Bool],
675 )
676 }
677}