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}