Skip to main content

geam_core/plan/module/expression/
string.rs

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