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}