Skip to main content

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

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