Skip to main content

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

1use crate::plan::CustomFieldAccess;
2use crate::plan::{
3    BoolExpr, CaptureArg, ConstantNilFunctionInstantiation, FloatExpr, FunctionFunctionExpr,
4    FunctionInstantiation, FunctionListExpr, FunctionType, IntExpr, NilFunctionLocalId,
5    NilFunctionReference, PanicExpr, Step, StringExpr, TupleExpr,
6};
7use ecow::EcoString;
8use num_bigint::BigInt;
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct NilFunctionExpr {
12    type_: FunctionType,
13    kind: NilFunctionExprKind,
14}
15
16#[derive(Debug, Clone, PartialEq)]
17pub(crate) enum NilFunctionExprKind {
18    Constant(ConstantNilFunctionInstantiation),
19    Reference(NilFunctionReference),
20    Closure {
21        function: FunctionInstantiation,
22        captures: Vec<CaptureArg>,
23    },
24    LocalGet {
25        local: NilFunctionLocalId,
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<NilFunctionExpr>,
55        false_: Box<NilFunctionExpr>,
56    },
57    IntCase {
58        subject: Box<IntExpr>,
59        clauses: Vec<(BigInt, NilFunctionExpr)>,
60        fallback: Box<NilFunctionExpr>,
61    },
62    StringCase {
63        subject: Box<StringExpr>,
64        clauses: Vec<(EcoString, NilFunctionExpr)>,
65        fallback: Box<NilFunctionExpr>,
66    },
67    FloatCase {
68        subject: Box<FloatExpr>,
69        clauses: Vec<(f64, NilFunctionExpr)>,
70        fallback: Box<NilFunctionExpr>,
71    },
72    Block {
73        steps: Vec<Step>,
74        return_: Box<NilFunctionExpr>,
75    },
76}
77
78impl NilFunctionExpr {
79    pub(crate) fn constant(value: ConstantNilFunctionInstantiation, type_: FunctionType) -> Self {
80        Self {
81            type_,
82            kind: NilFunctionExprKind::Constant(value),
83        }
84    }
85
86    pub(crate) fn reference(value: NilFunctionReference) -> Self {
87        let type_ = value.instantiation().shape().type_();
88        Self {
89            type_,
90            kind: NilFunctionExprKind::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: NilFunctionExprKind::Closure { function, captures },
102        }
103    }
104
105    pub(crate) fn local_get(
106        local: NilFunctionLocalId,
107        name: EcoString,
108        type_: FunctionType,
109    ) -> Self {
110        Self {
111            type_,
112            kind: NilFunctionExprKind::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: NilFunctionExprKind::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: NilFunctionExprKind::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: NilFunctionExprKind::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: NilFunctionExprKind::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: NilFunctionExprKind::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: NilFunctionExprKind::Panic(panic),
205        }
206    }
207
208    pub(crate) fn bool_case(
209        subject: BoolExpr,
210        true_: NilFunctionExpr,
211        false_: NilFunctionExpr,
212    ) -> Self {
213        Self {
214            type_: true_.type_.clone(),
215            kind: NilFunctionExprKind::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, NilFunctionExpr)>,
226        fallback: NilFunctionExpr,
227    ) -> Self {
228        Self {
229            type_: fallback.type_.clone(),
230            kind: NilFunctionExprKind::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, NilFunctionExpr)>,
241        fallback: NilFunctionExpr,
242    ) -> Self {
243        Self {
244            type_: fallback.type_.clone(),
245            kind: NilFunctionExprKind::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, NilFunctionExpr)>,
256        fallback: NilFunctionExpr,
257    ) -> Self {
258        Self {
259            type_: fallback.type_.clone(),
260            kind: NilFunctionExprKind::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_: NilFunctionExpr) -> Self {
269        Self {
270            type_: return_.type_.clone(),
271            kind: NilFunctionExprKind::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) -> &NilFunctionExprKind {
283        &self.kind
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use super::{NilFunctionExpr, NilFunctionExprKind};
290    use crate::plan::{
291        BoolExpr, Expr, FunctionFunctionExpr, FunctionFunctionReference, FunctionInstantiation,
292        FunctionShape, FunctionType, IntExpr, NilFunctionLocalId, NilFunctionReference, Step,
293        StringExpr, ValueShape, ValueType, monomorphic_function_instantiation,
294    };
295
296    #[test]
297    fn nil_function_expr_kind_accessors() {
298        assert_eq!(
299            function_value().kind(),
300            &NilFunctionExprKind::Reference(NilFunctionReference::new(function_instantiation())),
301        );
302        assert_eq!(
303            NilFunctionExpr::closure(function_instantiation(), Vec::new(), function_type(),).kind(),
304            &NilFunctionExprKind::Closure {
305                function: function_instantiation(),
306                captures: Vec::new(),
307            },
308        );
309        assert_eq!(
310            NilFunctionExpr::local_get(NilFunctionLocalId(0), "f".into(), function_type()).kind(),
311            &NilFunctionExprKind::LocalGet {
312                local: NilFunctionLocalId(0),
313                name: "f".into(),
314            },
315        );
316        assert_eq!(
317            NilFunctionExpr::call(
318                function_returning_function_instantiation(),
319                Vec::new(),
320                function_type(),
321            )
322            .kind(),
323            &NilFunctionExprKind::Call {
324                function: function_returning_function_instantiation(),
325                args: Vec::new(),
326                type_: function_type(),
327                site: crate::plan::HostCallSite::unknown(),
328            },
329        );
330        assert_eq!(
331            NilFunctionExpr::function_call(function_function_value(), Vec::new(), function_type())
332                .kind(),
333            &NilFunctionExprKind::FunctionCall {
334                function: Box::new(function_function_value()),
335                args: Vec::new(),
336                type_: function_type(),
337                site: crate::plan::HostCallSite::unknown(),
338            },
339        );
340        assert_eq!(
341            NilFunctionExpr::tuple_index(tuple_expr(), 0, function_type()).kind(),
342            &NilFunctionExprKind::TupleIndex {
343                tuple: Box::new(tuple_expr()),
344                index: 0,
345                type_: function_type(),
346            },
347        );
348        assert_eq!(
349            NilFunctionExpr::bool_case(BoolExpr::value(true), function_value(), function_value(),)
350                .kind(),
351            &NilFunctionExprKind::BoolCase {
352                subject: Box::new(BoolExpr::value(true)),
353                true_: Box::new(function_value()),
354                false_: Box::new(function_value()),
355            },
356        );
357        assert_eq!(
358            NilFunctionExpr::int_case(
359                IntExpr::value(1.into()),
360                vec![(1.into(), function_value())],
361                function_value(),
362            )
363            .kind(),
364            &NilFunctionExprKind::IntCase {
365                subject: Box::new(IntExpr::value(1.into())),
366                clauses: vec![(1.into(), function_value())],
367                fallback: Box::new(function_value()),
368            },
369        );
370        assert_eq!(
371            NilFunctionExpr::string_case(
372                StringExpr::value("one".into()),
373                vec![("one".into(), function_value())],
374                function_value(),
375            )
376            .kind(),
377            &NilFunctionExprKind::StringCase {
378                subject: Box::new(StringExpr::value("one".into())),
379                clauses: vec![("one".into(), function_value())],
380                fallback: Box::new(function_value()),
381            },
382        );
383        assert_eq!(
384            NilFunctionExpr::float_case(
385                crate::plan::FloatExpr::value(1.0),
386                vec![(1.0, function_value())],
387                function_value(),
388            )
389            .kind(),
390            &NilFunctionExprKind::FloatCase {
391                subject: Box::new(crate::plan::FloatExpr::value(1.0)),
392                clauses: vec![(1.0, function_value())],
393                fallback: Box::new(function_value()),
394            },
395        );
396        assert_eq!(
397            NilFunctionExpr::block(
398                vec![Step::evaluate(Expr::int(IntExpr::value(1.into())))],
399                function_value(),
400            )
401            .kind(),
402            &NilFunctionExprKind::Block {
403                steps: vec![Step::evaluate(Expr::int(IntExpr::value(1.into())))],
404                return_: Box::new(function_value()),
405            },
406        );
407    }
408
409    #[test]
410    fn nil_function_expr_type() {
411        assert_eq!(function_value().type_(), &function_type());
412    }
413
414    fn function_value() -> NilFunctionExpr {
415        NilFunctionExpr::reference(NilFunctionReference::new(function_instantiation()))
416    }
417
418    fn function_type() -> FunctionType {
419        FunctionType::new(vec![ValueType::Nil], ValueType::Nil)
420    }
421
422    fn function_function_value() -> FunctionFunctionExpr {
423        FunctionFunctionExpr::reference(
424            FunctionFunctionReference::new(function_returning_function_instantiation()),
425            function_type(),
426        )
427    }
428
429    fn function_instantiation() -> FunctionInstantiation {
430        monomorphic_function_instantiation(0, FunctionShape::from_function_type(function_type()))
431    }
432
433    fn function_returning_function_instantiation() -> FunctionInstantiation {
434        monomorphic_function_instantiation(
435            1,
436            FunctionShape::new(
437                Vec::new(),
438                ValueShape::Function(Box::new(FunctionShape::from_function_type(function_type()))),
439            ),
440        )
441    }
442
443    fn tuple_expr() -> crate::plan::TupleExpr {
444        crate::plan::TupleExpr::value(
445            vec![Expr::function(crate::plan::FunctionExpr::nil(
446                function_value(),
447            ))],
448            vec![ValueType::Function(Box::new(function_type()))],
449        )
450    }
451}