Skip to main content

geam_core/plan/module/expression/
bool.rs

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}