Skip to main content

geam_core/plan/module/expression/
int.rs

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