Skip to main content

geam_core/plan/module/expression/
bit_array.rs

1use super::{
2    BitArrayFunctionExpr, BitArrayListExpr, BoolExpr, CallArg, CustomFieldAccess, FloatExpr,
3    IntExpr, PanicExpr, StringExpr, TupleExpr, UtfCodepointExpr,
4};
5use crate::plan::{
6    BitArrayLocalId, ConstantBitArrayReference, FunctionInstantiation, PanicSite, Step,
7};
8use ecow::EcoString;
9use num_bigint::BigInt;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Endianness {
13    Big,
14    Little,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum StringEncoding {
19    Utf8,
20    Utf16(Endianness),
21    Utf32(Endianness),
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum FloatBitSize {
26    Sixteen,
27    ThirtyTwo,
28    SixtyFour,
29}
30
31#[derive(Debug, Clone, PartialEq)]
32pub(crate) struct BitArrayEvaluatedSize {
33    value: IntExpr,
34    unit: u8,
35}
36
37#[derive(Debug, Clone, PartialEq)]
38pub(crate) enum BitArrayBitsSize {
39    Fixed(usize),
40    Evaluated(BitArrayEvaluatedSize),
41}
42
43impl BitArrayEvaluatedSize {
44    pub(crate) fn new(value: IntExpr, unit: u8) -> Self {
45        Self { value, unit }
46    }
47
48    pub(crate) fn value(&self) -> &IntExpr {
49        &self.value
50    }
51
52    pub(crate) fn unit(&self) -> u8 {
53        self.unit
54    }
55}
56
57#[derive(Debug, Clone, PartialEq)]
58pub enum BitArraySegment {
59    Int {
60        value: IntExpr,
61        bit_size: usize,
62        endianness: Endianness,
63    },
64    EvaluatedInt {
65        value: IntExpr,
66        size: BitArrayEvaluatedSize,
67        endianness: Endianness,
68        site: PanicSite,
69    },
70    Float {
71        value: FloatExpr,
72        bit_size: FloatBitSize,
73        endianness: Endianness,
74    },
75    EvaluatedFloat {
76        value: FloatExpr,
77        size: BitArrayEvaluatedSize,
78        endianness: Endianness,
79        site: PanicSite,
80    },
81    String {
82        value: StringExpr,
83        encoding: StringEncoding,
84    },
85    UtfCodepoint {
86        value: UtfCodepointExpr,
87        encoding: StringEncoding,
88    },
89    Bits(BitArrayExpr),
90    SizedBits {
91        value: BitArrayExpr,
92        size: BitArrayBitsSize,
93        site: PanicSite,
94    },
95}
96
97#[derive(Debug, Clone, PartialEq)]
98pub struct BitArrayExpr {
99    kind: BitArrayExprKind,
100}
101
102#[derive(Debug, Clone, PartialEq)]
103pub(crate) enum BitArrayExprKind {
104    Value(Vec<BitArraySegment>),
105    Constant(ConstantBitArrayReference),
106    LocalGet {
107        local: BitArrayLocalId,
108        name: EcoString,
109    },
110    Call {
111        function: FunctionInstantiation,
112        args: Vec<CallArg>,
113        site: crate::plan::HostCallSite,
114    },
115    FunctionCall {
116        function: Box<BitArrayFunctionExpr>,
117        args: Vec<CallArg>,
118        site: crate::plan::HostCallSite,
119    },
120    TupleIndex {
121        tuple: Box<TupleExpr>,
122        index: usize,
123    },
124    CustomField(CustomFieldAccess),
125    ListIndex {
126        list: Box<BitArrayListExpr>,
127        index: usize,
128    },
129    Panic(PanicExpr),
130    BoolCase {
131        subject: Box<BoolExpr>,
132        true_: Box<BitArrayExpr>,
133        false_: Box<BitArrayExpr>,
134    },
135    IntCase {
136        subject: Box<IntExpr>,
137        clauses: Vec<(BigInt, BitArrayExpr)>,
138        fallback: Box<BitArrayExpr>,
139    },
140    StringCase {
141        subject: Box<StringExpr>,
142        clauses: Vec<(EcoString, BitArrayExpr)>,
143        fallback: Box<BitArrayExpr>,
144    },
145    FloatCase {
146        subject: Box<FloatExpr>,
147        clauses: Vec<(f64, BitArrayExpr)>,
148        fallback: Box<BitArrayExpr>,
149    },
150    Block {
151        steps: Vec<Step>,
152        return_: Box<BitArrayExpr>,
153    },
154}
155
156impl BitArrayExpr {
157    pub(crate) fn value(segments: Vec<BitArraySegment>) -> Self {
158        Self::new(BitArrayExprKind::Value(segments))
159    }
160
161    pub(in crate::plan::module) fn constant(reference: ConstantBitArrayReference) -> Self {
162        Self::new(BitArrayExprKind::Constant(reference))
163    }
164
165    pub(crate) fn local_get(local: BitArrayLocalId, name: EcoString) -> Self {
166        Self::new(BitArrayExprKind::LocalGet { local, name })
167    }
168
169    #[cfg(test)]
170    pub(crate) fn call(function: FunctionInstantiation, args: Vec<CallArg>) -> Self {
171        Self::call_at(function, args, crate::plan::HostCallSite::unknown())
172    }
173
174    pub(crate) fn call_at(
175        function: FunctionInstantiation,
176        args: Vec<CallArg>,
177        site: crate::plan::HostCallSite,
178    ) -> Self {
179        Self::new(BitArrayExprKind::Call {
180            function,
181            args,
182            site,
183        })
184    }
185
186    #[cfg(test)]
187    pub(crate) fn function_call(function: BitArrayFunctionExpr, args: Vec<CallArg>) -> Self {
188        Self::function_call_at(function, args, crate::plan::HostCallSite::unknown())
189    }
190
191    pub(crate) fn function_call_at(
192        function: BitArrayFunctionExpr,
193        args: Vec<CallArg>,
194        site: crate::plan::HostCallSite,
195    ) -> Self {
196        Self::new(BitArrayExprKind::FunctionCall {
197            function: Box::new(function),
198            args,
199            site,
200        })
201    }
202
203    pub(crate) fn tuple_index(tuple: TupleExpr, index: usize) -> Self {
204        Self::new(BitArrayExprKind::TupleIndex {
205            tuple: Box::new(tuple),
206            index,
207        })
208    }
209
210    pub(crate) fn custom_field(access: CustomFieldAccess) -> Self {
211        Self::new(BitArrayExprKind::CustomField(access))
212    }
213
214    pub(crate) fn list_index(list: BitArrayListExpr, index: usize) -> Self {
215        Self::new(BitArrayExprKind::ListIndex {
216            list: Box::new(list),
217            index,
218        })
219    }
220
221    pub(crate) fn panic(panic: PanicExpr) -> Self {
222        Self::new(BitArrayExprKind::Panic(panic))
223    }
224
225    pub(crate) fn bool_case(subject: BoolExpr, true_: Self, false_: Self) -> Self {
226        Self::new(BitArrayExprKind::BoolCase {
227            subject: Box::new(subject),
228            true_: Box::new(true_),
229            false_: Box::new(false_),
230        })
231    }
232
233    pub(crate) fn int_case(subject: IntExpr, clauses: Vec<(BigInt, Self)>, fallback: Self) -> Self {
234        Self::new(BitArrayExprKind::IntCase {
235            subject: Box::new(subject),
236            clauses,
237            fallback: Box::new(fallback),
238        })
239    }
240
241    pub(crate) fn string_case(
242        subject: StringExpr,
243        clauses: Vec<(EcoString, Self)>,
244        fallback: Self,
245    ) -> Self {
246        Self::new(BitArrayExprKind::StringCase {
247            subject: Box::new(subject),
248            clauses,
249            fallback: Box::new(fallback),
250        })
251    }
252
253    pub(crate) fn float_case(
254        subject: FloatExpr,
255        clauses: Vec<(f64, Self)>,
256        fallback: Self,
257    ) -> Self {
258        Self::new(BitArrayExprKind::FloatCase {
259            subject: Box::new(subject),
260            clauses,
261            fallback: Box::new(fallback),
262        })
263    }
264
265    pub(crate) fn block(steps: Vec<Step>, return_: Self) -> Self {
266        Self::new(BitArrayExprKind::Block {
267            steps,
268            return_: Box::new(return_),
269        })
270    }
271
272    pub(crate) fn kind(&self) -> &BitArrayExprKind {
273        &self.kind
274    }
275
276    fn new(kind: BitArrayExprKind) -> Self {
277        Self { kind }
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::{
284        BitArrayBitsSize, BitArrayEvaluatedSize, BitArrayExpr, BitArrayExprKind, BitArraySegment,
285        Endianness,
286    };
287    use crate::plan::{
288        BitArrayFunctionReference, BitArrayLocalId, BoolExpr, Expr, FloatExpr, FloatLocalId,
289        FunctionInstantiation, FunctionShape, IntExpr, IntLocalId, PanicSite, Step, StringExpr,
290        TupleExpr, ValueShape, ValueType, monomorphic_function_instantiation,
291    };
292    use num_bigint::BigInt;
293
294    #[test]
295    fn bit_array_expr_kind_accessors() {
296        let segments = vec![BitArraySegment::Int {
297            value: IntExpr::value(1.into()),
298            bit_size: 8,
299            endianness: Endianness::Big,
300        }];
301        assert_eq!(
302            BitArrayExpr::value(segments.clone()).kind(),
303            &BitArrayExprKind::Value(segments),
304        );
305        assert_eq!(
306            BitArrayExpr::local_get(BitArrayLocalId(0), "value".into()).kind(),
307            &BitArrayExprKind::LocalGet {
308                local: BitArrayLocalId(0),
309                name: "value".into(),
310            },
311        );
312        assert_eq!(
313            BitArrayExpr::call(function_instantiation(), Vec::new()).kind(),
314            &BitArrayExprKind::Call {
315                function: function_instantiation(),
316                args: Vec::new(),
317                site: crate::plan::HostCallSite::unknown(),
318            },
319        );
320        assert_eq!(
321            BitArrayExpr::function_call(function_expr(), Vec::new()).kind(),
322            &BitArrayExprKind::FunctionCall {
323                function: Box::new(function_expr()),
324                args: Vec::new(),
325                site: crate::plan::HostCallSite::unknown(),
326            },
327        );
328        assert_eq!(
329            BitArrayExpr::tuple_index(tuple_expr(), 0).kind(),
330            &BitArrayExprKind::TupleIndex {
331                tuple: Box::new(tuple_expr()),
332                index: 0,
333            },
334        );
335        assert_eq!(
336            BitArrayExpr::bool_case(
337                BoolExpr::value(true),
338                bit_array_value(1),
339                bit_array_value(2),
340            )
341            .kind(),
342            &BitArrayExprKind::BoolCase {
343                subject: Box::new(BoolExpr::value(true)),
344                true_: Box::new(bit_array_value(1)),
345                false_: Box::new(bit_array_value(2)),
346            },
347        );
348        assert_eq!(
349            BitArrayExpr::int_case(
350                IntExpr::value(1.into()),
351                vec![(1.into(), bit_array_value(1))],
352                bit_array_value(2),
353            )
354            .kind(),
355            &BitArrayExprKind::IntCase {
356                subject: Box::new(IntExpr::value(1.into())),
357                clauses: vec![(BigInt::from(1), bit_array_value(1))],
358                fallback: Box::new(bit_array_value(2)),
359            },
360        );
361        assert_eq!(
362            BitArrayExpr::string_case(
363                StringExpr::value("one".into()),
364                vec![("one".into(), bit_array_value(1))],
365                bit_array_value(2),
366            )
367            .kind(),
368            &BitArrayExprKind::StringCase {
369                subject: Box::new(StringExpr::value("one".into())),
370                clauses: vec![("one".into(), bit_array_value(1))],
371                fallback: Box::new(bit_array_value(2)),
372            },
373        );
374        assert_eq!(
375            BitArrayExpr::float_case(
376                FloatExpr::value(1.0),
377                vec![(1.0, bit_array_value(1))],
378                bit_array_value(2),
379            )
380            .kind(),
381            &BitArrayExprKind::FloatCase {
382                subject: Box::new(FloatExpr::value(1.0)),
383                clauses: vec![(1.0, bit_array_value(1))],
384                fallback: Box::new(bit_array_value(2)),
385            },
386        );
387        assert_eq!(
388            BitArrayExpr::block(
389                vec![Step::evaluate(Expr::bit_array(bit_array_value(1)))],
390                bit_array_value(2),
391            )
392            .kind(),
393            &BitArrayExprKind::Block {
394                steps: vec![Step::evaluate(Expr::bit_array(bit_array_value(1)))],
395                return_: Box::new(bit_array_value(2)),
396            },
397        );
398    }
399
400    #[test]
401    fn evaluated_segment_owners_preserve_value_size_and_failure_site() {
402        let site = PanicSite::new(
403            "main".into(),
404            "main".into(),
405            crate::plan::SourceSpan::new(4, 20),
406        );
407        let int_size =
408            BitArrayEvaluatedSize::new(IntExpr::local_get(IntLocalId(1), "int_size".into()), 2);
409        let float_size =
410            BitArrayEvaluatedSize::new(IntExpr::local_get(IntLocalId(2), "float_size".into()), 4);
411        let bits_size =
412            BitArrayEvaluatedSize::new(IntExpr::local_get(IntLocalId(3), "bits_size".into()), 8);
413        let segments = vec![
414            BitArraySegment::EvaluatedInt {
415                value: IntExpr::local_get(IntLocalId(0), "int_value".into()),
416                size: int_size.clone(),
417                endianness: Endianness::Little,
418                site: site.clone(),
419            },
420            BitArraySegment::EvaluatedFloat {
421                value: FloatExpr::local_get(FloatLocalId(0), "float_value".into()),
422                size: float_size.clone(),
423                endianness: Endianness::Big,
424                site: site.clone(),
425            },
426            BitArraySegment::SizedBits {
427                value: BitArrayExpr::local_get(BitArrayLocalId(0), "bits".into()),
428                size: BitArrayBitsSize::Fixed(12),
429                site: site.clone(),
430            },
431            BitArraySegment::SizedBits {
432                value: BitArrayExpr::local_get(BitArrayLocalId(1), "dynamic_bits".into()),
433                size: BitArrayBitsSize::Evaluated(bits_size.clone()),
434                site: site.clone(),
435            },
436        ];
437
438        assert_eq!(
439            BitArrayExpr::value(segments.clone()).kind(),
440            &BitArrayExprKind::Value(segments),
441        );
442        assert_eq!(
443            int_size.value(),
444            &IntExpr::local_get(IntLocalId(1), "int_size".into())
445        );
446        assert_eq!(int_size.unit(), 2);
447        assert_eq!(float_size.unit(), 4);
448        assert_eq!(bits_size.unit(), 8);
449    }
450
451    fn bit_array_value(value: u8) -> BitArrayExpr {
452        BitArrayExpr::value(vec![BitArraySegment::Int {
453            value: IntExpr::value(value.into()),
454            bit_size: 8,
455            endianness: Endianness::Big,
456        }])
457    }
458
459    fn function_expr() -> crate::plan::BitArrayFunctionExpr {
460        crate::plan::BitArrayFunctionExpr::reference(BitArrayFunctionReference::new(
461            function_instantiation(),
462        ))
463    }
464
465    fn function_instantiation() -> FunctionInstantiation {
466        monomorphic_function_instantiation(0, FunctionShape::new(Vec::new(), ValueShape::BitArray))
467    }
468
469    fn tuple_expr() -> TupleExpr {
470        TupleExpr::value(
471            vec![Expr::bit_array(bit_array_value(1))],
472            vec![ValueType::BitArray],
473        )
474    }
475}