Skip to main content

geam_core/plan/module/expression/function/
int.rs

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