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}