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}